# Vue 文档初探(一): Vue 实例

源码地址

# 创建实例

let vm = new Vue({
  //options
});
1
2
3

当一个 Vue 实例创建后, 它的options都会添加到reactivity system里. 当options的属性变化后, 视图(view)就会响应(react), 然后更新.

无论从实例上修改还是在data属性里修改, Vue 都会进行响应并对数据进行更新, 但是对于没有被添加到reactivity system里的属性是不会响应更新的, 比如给实例vm添加属性b, data是读不到b属性的.这是由于 Vue 使用了Object.defineProperty()进行监听的, 它只对调用的对象已有的属性进行监听, 无法监听到新增属性.

# 不要跟踪变化

如果你不想让你的属性被reactivity system监听并更新, 可以使用Object.freeze(obj).

<div id="app">
  <p>{{foo}}</p>
  <button @click="foo = 'baz'">change</button>
  //Error in v-on handler: "TypeError:
  //Cannot assign to read only property 'foo' of object '#<Object>'"
</div>
1
2
3
4
5
6
let obj = {
  foo: "bar"
};
Object.freeze(obj);
let vm = new Vue({
  el: "#app",
  data: obj
});
1
2
3
4
5
6
7
8

# 暴露出的属性

Vue 会暴露出实例的属性让我们在外部也可以使用 Vue 提供的属性和方法.为了和用户自定义的属性相区别, Vue 实例的属性都会在首字符加一个$.

let data = { a: 1 };
let vm = new Vue({
  el: "#app",
  data: data
});

console.log(vm.$data === data); //true
console.log(vm.$el === document.querySelector("#app")); //true

vm.$watch("a", (newValue, oldValue) => {
  console.log(newValue);
  console.log(oldValue);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
<div id="app">
  {{a}}
  <button @click="a+=1">+1</button> // 2 1
</div>
1
2
3
4

# 生命周期钩子

当我们创建一个 Vue 实例时, 每一个实例都会经历一系列的初始化步骤. 比如设置数据观察, 模板编译, 挂载实例到 DOM 上, 随着数据更新而更新 DOM. 在这一系列过程里还会运行一些叫生命周期钩子(lifecycle hooks)的函数, 它使得用户可以添加自己的代码到具体的每个阶段. 常用的钩子有created, mounted, updated, destroyed.

new Vue({
  data: {
    a: 1
  },
  created: function() {
    // `this` points to the vm instance
    console.log("a is: " + this.a);
  }
});
// => "a is: 1"
1
2
3
4
5
6
7
8
9
10

在使用钩子函数时, 最好不要使用箭头函数. 钩子函数里的this指向调用它的实例. lifecycle

# 指令

Vue 内置了指令给我们使用, 指令都是以v-作为前缀的.它是许多功能的一个集合.如v-if, v-bind, v-on.Vue 还提供用户自定义指令的功能, 实在强大.

<p v-if="seen">Now you see me</p>

上面这个代码使用了v-if指令, 它将根据实例里dataseen的真值来判断是否显示这个p标签.

# 参数

指令也可以带上参数, 见下面的代码:

<a v-on:click="doSomething"> ... </a>

click就是指令的参数. 它监听click事件, 然后触发doSomething.

# 动态参数

上面我们将参数写死了, 动态参数可以在data里写我们的属性, 在不造成 bug 的情况下可以任意修改, 增加了灵活性.

let vm = new Vue({
  el: "#app",
  template: `<div>
    <p>hello</p>
    <a :[attributeName]="url">link</a>
  </div>`,
  data: {
    attributeName: "href",
    url: "https://baidu.com"
  }
});
1
2
3
4
5
6
7
8
9
10
11

# 修饰符

修饰符写在指令的最后面, 表示指令要以某种方式绑定.比如, 我们绑定一个form表单提交的事件, 并且阻止默认行为.

<form v-on:submit.prevent="onSubmit"> ... </form>

.prevent就是一个修饰符, 它由 Vue 提供.

# sync修饰符

我们会遇到这样一个场景: 父组件的 data 通过prop传入子组件里, 子组件会在某件事发生后要修改prop的值. 在这个场景里, 如果直接修改prop会得到一个报错信息.


















 



// Father
new Vue({
  data() {
    return {
      n: 1
    };
  },
  template: `
    <Son :count="n">
  `
});

// Son
new Vue({
  props: ["count"],
  template: `
    <p>{{count}}</p>
    <button @click="count+=1">+1</button> // 报错!!
  `
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

有两种办法可以解决:

# 传递 message 到父组件, 在父组件更改









 













 



// Father
new Vue({
  data() {
    return {
      n: 1
    };
  },
  template: `
    <Son :count="n" @increment="handleIncrement">
  `,
  methods: {
    handleIncrement() {
      this.n += 1;
    }
  }
});

// Son
new Vue({
  props: ["count"],
  template: `
    <p>{{count}}</p>
    <button @click="$emit('increment')">+1</button>
  `
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 使用.sync修饰符









 








 



// Father
new Vue({
  data() {
    return {
      n: 1
    };
  },
  template: `
    <Son :count="n" @update:increment="n = $event">// $event的值就是在子组件$emit()的第二个参数
  `
});

// Son
new Vue({
  props: ["count"],
  template: `
    <p>{{count}}</p>
    <button @click="$emit('update:increment', count+1)">+1</button>
  `
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

由于上面的代码范式很常用或是很重要, Vue 把它封装进内置的修饰符里了, 取名叫sync.

// Father
<Son :count.sync="n">

// Son
$emit('update:count', val) //发射信息是约定好的, 不要修改
1
2
3
4
5

# data既是对象又是函数

在 Vue 里面, data这个选项有时写成对象, 有时写成函数. 它们是有区别的.

// object syntax
data: {
  // options
}

// function syntax
data: function(){
  return {
    // options
  }
}
1
2
3
4
5
6
7
8
9
10
11

在非组件里使用对象语法是完全没有问题的, 而一旦在组件里并且考虑复用组件时则必须使用函数语法. 因为考虑到组件的复用, 我们希望每个组件的状态是各自独立的. 使用 object syntax 会使复用组件使用同一个data对象. 所以我们使用 function syntax 使得每次实例化组件然后调用data函数时都返回一个新的对象.