# Vue 文档初探(一): Vue 实例
# 创建实例
let vm = new Vue({
//options
});
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>
2
3
4
5
6
let obj = {
foo: "bar"
};
Object.freeze(obj);
let vm = new Vue({
el: "#app",
data: obj
});
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);
});
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>
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"
2
3
4
5
6
7
8
9
10
在使用钩子函数时, 最好不要使用箭头函数. 钩子函数里的this
指向调用它的实例.
# 指令
Vue 内置了指令给我们使用, 指令都是以v-
作为前缀的.它是许多功能的一个集合.如v-if
, v-bind
, v-on
.Vue 还提供用户自定义指令的功能, 实在强大.
<p v-if="seen">Now you see me</p>
上面这个代码使用了v-if
指令, 它将根据实例里data
的seen
的真值来判断是否显示这个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"
}
});
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> // 报错!!
`
});
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>
`
});
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>
`
});
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) //发射信息是约定好的, 不要修改
2
3
4
5
# data
既是对象又是函数
在 Vue 里面, data
这个选项有时写成对象, 有时写成函数. 它们是有区别的.
// object syntax
data: {
// options
}
// function syntax
data: function(){
return {
// options
}
}
2
3
4
5
6
7
8
9
10
11
在非组件里使用对象语法是完全没有问题的, 而一旦在组件里并且考虑复用组件时则必须使用函数语法. 因为考虑到组件的复用, 我们希望每个组件的状态是各自独立的. 使用 object syntax 会使复用组件使用同一个data
对象. 所以我们使用 function syntax 使得每次实例化组件然后调用data
函数时都返回一个新的对象.