# Vue实例对象的数据选项
一般地,当模板内容较简单时,使用data选项配合表达式即可。涉及到复杂逻辑时,则需要用到methods、computed、watch等方法。本文将详细介绍Vue实例对象的数据选项
# data
data是Vue实例的数据对象。Vue将会递归将 data 的属性转换为getter/setter
,从而让data属性能响应数据变化。
【注意】
不应该对 data 属性使用箭头函数
<script>
var data = { message: 'Hello Vue!' }
var vm = new Vue({
el: '#app',
data: data
})
console.log(vm);
</script>
Vue实例创建之后,可以通过vm.$data
或者vm._data
访问原始数据对象
Vue实例也代理了data对象上所有的属性
var data = { message: 'Hello Vue!' }
var vm = new Vue({
el: '#app',
data: data
})
console.log(vm.$data === data); // true
console.log(vm.message); //'Hello Vue!'
console.log(vm.$data.message); //'Hello Vue!'
代理
被代理的属性是响应的,也就是说值的任何改变都是触发视图的重新渲染。设置属性也会影响到原始数据,反之亦然
vm._data.message = "我是修改后的message" // 视图将显示更改为 我是修改后的message
WARNING
以 _ 或 $ 开头的属性不会被Vue实例代理,因为它们可能和Vue内置的属性或方法冲突。可以使用例如vm.$data._property的方式访问这些属性
const data = {
message: "Hello Vue!",
_name: "张三",
};
const vm = new Vue({
el: "#app",
data: data,
});
console.log(vm.message); // Hello Vue!
console.log(vm._name); // undefined
console.log(vm.$data._name); // 张三
console.log(vm._data._name); // 张三
# computed
- 计算属性函数computed将被混入到Vue实例中。
- 所有getter和setter的this上下文自动地绑定为Vue实例
【注意】
不应该使用箭头函数来定义计算属性函数
computed示例
<div id="app">
<p>原始字符串: "{{ message }}"</p>
<p>反向字符串: "{{ reversedMsg }}"</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Hello'
},
computed: {
reversedMsg() {
return this.message.split('').reverse().join('')
}
}
})
</script>
真实渲染结果如下
<div id="app">
<p>原始字符串: "Hello"</p>
<p>反向字符串: "olleH"</p>
</div>
声明的计算属性 reversedMsg 。提供的函数将作为属性 vm.reversedMsg
的getter
TIP
vm.reversedMessage
的值始终取决于vm.message
的值。- 可以像绑定普通属性一样在模板中绑定计算属性。当
vm.message
发生改变时,所有依赖于vm.reversedMessage
的绑定也会更新 - reversedMessage属性可以理解为由 message派生出的属性
console.log(vm.reversedMsg) // -> 'olleH'
vm.message = "Vue" // 改变data中的message
// 再打印reversedMsg
console.log(vm.reversedMsg) // -> 'euV'
DANGER
// 如果修改 vm.reversedMsg // vm.reversedMessage依赖于vm.message的值,vm.reversedMessage本身并不能被赋值 // 计算属性默认只有 getter ,不过在需要时也可以提供一个 setter。代码示例如下
# 【setter】
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
<!--完整写法-->
// computed: {
// fullName: {
// get(){
// return this.firstName + ' ' + this.lastName
// }
// }
}
})
</script>
注意
需要注意的是,不是说我们更改了getter里使用的变量,就会触发computed的更新,前提是computed里的值必须要在模板里使用才行。
以下代码只会打印 updated
<div id="demo">
<!-- <p> {{ fullName }} </p> -->
<input type="text" v-model="firstName">
<input type="text" v-model="lastName">
</div>
var vm = new Vue({
el: '#demo',
data: {
firstName: 'zhang',
lastName: 'san'
},
computed: {
fullName: function () {
console.log('computed getter...')
return this.firstName + ' ' + this.lastName
}
},
updated () {
console.log('updated')
}
})
添加setter
<div id="demo">
<p> {{ fullName }} </p>
<input type="text" v-model="fullName">
<input type="text" v-model="firstName">
<input type="text" v-model="lastName">
</div>
computed: {
fullName: {
// getter 方法
get(){
console.log('computed getter...')
return this.firstName + ' ' + this.lastName
},
// setter 方法
set(newValue){
console.log('computed setter...')
let names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
return this.firstName + ' ' + this.lastName
}
}
},
updated () {
console.log('updated')
}
<!--
v-model="fullName",如果我们这里直接修改了fullName的值,
那么就会触发setter,同时也会触发getter以及updated函数。
其执行顺序是setter -> getter -> updated
-->
// console.log('computed setter...')
// console.log('computed getter...')
// console.log('updated')
注意
- 并不是触发了setter也就会触发getter,他们两个是相互独立的。
- 我们这里修改了fullName会触发getter是因为setter函数里有改变firstName 和 lastName 值的代码。
- 如果注释掉上边的setter中修改firstName 和lastName的代码后就不会执行getter 如下
set(newValue){
console.log('computed setter...')
// let names = newValue.split(' ')
// this.firstName = names[0]
// this.lastName = names[names.length - 1]
return this.firstName + ' ' + this.lastName
}
// 执行如下 console.log('computed setter...') console.log('updated')
# methods
通过调用表达式中的 methods 也可以达到 computed 同样的效果
WARNING
[注意] 不应该使用箭头函数来定义methods函数
<div id="app">
<p>原始字符串: "{{ message }}"</p>
<p>反向字符串: "{{ reversedMsg() }}"</p>
</div>
data: {
message: 'Hello'
},
methods: {
reversedMsg() {
return this.message.split('').reverse().join('')
}
}
- 对于最终的渲染结果,两种方式确实是相同的
- 不同的是计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。
- 这就意味着只要 message 还没有发生改变,多次访问 reversedMsg 计算属性会立即返回之前的计算结果,而不必再次执行函数。
TIP
- 假设有一个性能开销比较大的的计算属性A,它需要遍历一个极大的数组和做大量的计算生成。可能有其他的计算属性依赖于计算属性 A。就需要缓存这一特性,性能也会更+
- 如果没有缓存,将不可避免的多次执行A的getter!如果不希望有缓存,则用 methods 替代
# watch
- Vue提供了一种通用的方式来观察和响应Vue实例上的数据变动:watch选项。
- watch属性是一个对象,键是需要观察的表达式,值是对应回调函数,回调函数得到的参数为新值和旧值。
WARNING
[注意] 不应该使用箭头函数来定义 watch 函数
示例
<div id="app">
<button @click="num++">a加1</button>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
num: 1
},
watch: {
num(val, oldVal) {
// 只要num发生变化 都将打印以下内容
console.log(`num的新值:${val},num的旧值:${oldVal}`)
}
}
})
</script>
# 【$watch】
除了使用数据选项中的watch方法以外,还可以使用实例对象的$watch方法, 该方法的返回值是一个取消观察函数,用来停止触发回调
<script>
var vm = new Vue({
el: '#app',
data: {
num: 1
}
})
var unwatch = vm.$watch('num',function(val, oldVal){
if(val === 10){
// 当num的值更新到10时,触发unwatch(),来取消观察。
// 点击按钮时,a的值仍然会变化,但是不再触发watch的回调函数
unwatch();
}
console.log(`num的新值:${val},num的旧值:${oldVal}`)
})
</script>
← vue入门基础 Vue 生命周期的理解 →