聊聊vue的计算属性和帧听器
vue的计算属性computed和侦听器watch都是监听数据变化。
computed
顾名思义,computed 中文为计算;所以其在vue单文件组件中做的就是对数据进行简单的一些逻辑计算,这在项目开发中很方便我们队原始数据处理。** 重要的是计算属性基于它们的响应式依赖进行缓存的。**只有当响应依赖关系变了即值发生变化了才会重新计算。否则,直接利用缓存,这样既避免多次调用函数又提升性能。
const vm = new Vue({
el: '#demo',
data: {
firstName: 'kevin',
lastName: 'Xie'
},
computed: {
fullName () {
return this.firstName + ' ' + this.lastName
}
}
})
computed 有两个属性getter 和 setter,上面我们只用到了getter属性,默认是getter属性,如果需要主动去改变getter的值,可以通过setter来实现。
// ...
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
// ...
watch
watch 则多数监听数据改变去执行异步操作和逻辑复杂的操作。同样watch也是在当值发生改变才会触发,不过没有缓存机制。
const vm = new Vue({
el: '#demo2',
data: {
visible: false
},
watch: {
visible (newVal, oldVal) {
// ...some code
}
}
})
watch的类型可以是{ [key: string]: string | Function | Object | Array }
一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。
var vm = new Vue({
data: {
a: 1,
b: 2,
c: 3,
d: 4,
e: {
f: {
g: 5
}
}
},
watch: {
a: function (val, oldVal) {
console.log('new: %s, old: %s', val, oldVal)
},
// 方法名
b: 'someMethod',
// 该回调会在任何被侦听的对象的 property 改变时被调用,不论其被嵌套多深
c: {
handler: function (val, oldVal) { /* ... */ },
deep: true
},
// 该回调将会在侦听开始之后被立即调用
d: {
handler: 'someMethod',
immediate: true
},
e: [
'handle1',
function handle2 (val, oldVal) { /* ... */ },
{
handler: function handle3 (val, oldVal) { /* ... */ },
/* ... */
}
],
// watch vm.e.f's value: {g: 5}
'e.f': function (val, oldVal) { /* ... */ }
}
})
vm.a = 2 // => new: 2, old: 1
** 注意,不应该使用箭头函数来定义 watcher 函数 (例如 searchQuery: newValue => this.updateAutocomplete(newValue))。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.updateAutocomplete 将是 undefined**
有时候computed可以和watch配合使用,比如你要同时监听两个值得变化。可以这样写:
const vm = new Vue({
el: '#demo3',
data: {
value1: '',
value2: ''
},
computed: {
doubleVal () {
return {
val1: this.value1,
val2: this.value2
}
}
},
watch: {
doubleVal(v) {
console.log(v) // 这里的v就包括两个值
}
}
})
还有一点在开发可能会遇到,就是watch一个对象时,只有当给对象赋值了才触发watch,但我们需求是要在初始化对象时就触发,这个时候deep属性就派上用场了。
const vm = new Vue({
el: '#demo4',
data: {
obj: {
a: 1,
b: 'test'
}
},
watch: {
obj: {
handler(v) {
console.log(v) // 不会执行
}
}
}
})
const vm = new Vue({
el: '#demo5',
data: {
obj: {
a: 1,
b: 'test'
}
},
watch: {
obj: {
handler(v) {
console.log(v) // {a: 1, b: 'test'}
},
deep: true
}
}
})
但是这样会影响性能,使得对象某一个属性发生改变时vue就啊哟深度遍历整个对象,对每个属性都会触发handler函数,建议采用字符串形式监听
const vm = new Vue({
el: '#demo6',
data: {
obj: {
a: 1,
b: ''
}
},
watch: {
'obj.a': {
handler(v) {
console.log(v) // 1
}
}
}
})
还有一个场景是当某个值初始化但watch没有监听到,然而我们同样需要立即监听,则immediate属性派上用场了。
const vm = new Vue({
el: '#demo7',
data: {
say: 'hello world'
},
watch: {
say: {
handler(v) {
console.log(v) // 不会执行
}
}
}
})
const vm = new Vue({
el: '#demo8',
data: {
say: 'hello world'
},
watch: {
say: {
handler(v) {
console.log(v) // hello world
},
immediate: true
}
}
})
watch在不用的时候需要注销它,在单文件组件销毁时vue会帮我们自动注销,但如果我们没在单文件组件使用,app.$watch调用后会返回一个值,就是unWatch方法,你要注销 watch 只要调用unWatch方法就可以了。
const unWatch = app.$watch('text', (newVal, oldVal) => {
console.log(`${newVal} : ${oldVal}`)
})
unWatch() // 手动注销watch
好了,今天vue的计算属性和帧听器就聊到这了, 欢迎大家批评指正。