vue2.x之监听属性
什么是监听属性?
所谓监听就是对内置对象的状态或者属性变化进行监听并且做出反应的响应,监听属性,意思就是可以监视其他数据的变化。
基本用法
使用watch配置项,在配置项里面写上要监视的属性,每次属性值的变化都会触发handler函数回调,也可以监视计算属性的变化。
<!--template 模版--> <template> <div class="hello"> <input type="text" v-model="firstName"> </div> </template> <script> export default { name: 'Vue2LearnHelloWorld', props: ['title'], data() { return { firstName: '', }; }, watch: { firstName: { handler: function (newVal, oldVal) { console.log(`'firstName变化了,最新的值:${newVal},上一次的值:${oldVal}`); } } }, }; </script>
这时只要一输入值就能监听到firstName的变化
即时监听
在有的应用场景中,我们需要页面从一开始的时候就开始监听变化,而不是只有在数据变化的时候才开始执行里面的handler函数,这时候就需要用到一个属性immediate。
watch: { firstName: { handler: function (newVal, oldVal) { console.log(`'firstName变化了,最新的值:${newVal},上一次的值:${oldVal}`); }, immediate: true } },
这时页面一挂载进来就能监听,执行handler函数
深度监听
当我们的对象有多层结构的时候,我们要监听的对象的属性很多,避免一个一个属性单独写,这个时候用到深度监听。
在watch配置中,监视属性对象中,配置deep 设置为 true 用于监听多级对象或者数组内部值的变化
watch:{ //监视多级结构中所有属性的变化 friends:{ handler(newValue,oldValue){ console.log(newValue,oldValue,"aa") }, deep:true, //开启深度监听 } }
🌰示例
<!--template 模版--> <template> <div class="hello"> <input type="text" v-model="person.name"> <input type="text" v-model="person.age"> </div> </template> <script> export default { name: 'Vue2LearnHelloWorld', props: ['title'], data() { return { person:{ name:'刘德华', age:18 } }; }, watch: { firstName: { handler: function (newVal, oldVal) { console.log(`'person的变化了,最新的值:${newVal},上一次的值:${oldVal}`); }, immediate: true, deep:true } }, }; </script>
上面这个例子只有加了deep属性才能监听到person的变化,否则是不能监听到,因为person的属性是个引用类型变量,person属性值存的实际上是一个地址,改变person对象的属性值对象本身是不变的,应用地址也不会改变,person就不会被监听到,只有加了deep属性才可以被监听到。
简写形式
上面是watch的完整形式,如果只是想监听数据,而不需要使用deep属性和immediate属性的话,可以采用下面的简写属性。
⏰ 完整形式
// 完整形式 firstName: { handler: function(newVal, oldVal) { console.log('firstName变化了,这是最新的值:', newVal); } }
⏰ 简写形式
// 简写形式 firstName(newVal, oldVal) { console.log('firstName变化了,这是最新的值:', newVal); },
原理
function initWatch (vm: Component, watch: Object) { // 1.遍历watch for (const key in watch) { const handler = watch[key] if (Array.isArray(handler)) { for (let i = 0; i < handler.length; i++) { createWatcher(vm, key, handler[i]) } } else { // 2.创建watcher createWatcher(vm, key, handler) } } }
function createWatcher ( vm: Component, expOrFn: string | Function, handler: any, options?: Object ) { //监听属性的值是一个对象,包含handler,deep,immediate if (isPlainObject(handler)) { options = handler handler = handler.handler } //如果回调函数是一个字符串,从VM中获取 if (typeof handler === 'string') { handler = vm[handler] } //expOrFn是key, options是watch的全部选项 return vm.$watch(expOrFn, handler, options) }
watch可以使用异步函数
很多时候,监听数据变化后,我们需要进行一些异步操作,比如定时器回调:
firstName(newVal, oldVal) { setTimeout(() => { console.log('firstName变化了,这是最新的值:', newVal); }) },
计算属性和监听属性的区别
计算属性是依赖的值改变后重新计算结果更新DOM,会进行缓存。
属性监听的是属性值,当定义的值发生变化时,执行相对应的函数。
最主要的用途区别:
计算属性不能执行异步任务。计算属性一般不会用来向服务器请求或者执行异步任务,因为耗时可能会比较长,我们的计算属性要实时更新。所以这个异步任务就可以用监听属性来做。⏰ 总之一句话:computed能实现的,watch都能实现,computed不能实现的,watch也能实现
上面一篇文章我们介绍过计算属性,还用了姓和名列举了全名的案例,这个案例也可以通过watch监听来实现。
<!--template 模版--> <template> <div class="hello"> <input type="text" v-model="firstName"><br> <input type="text" v-model="lastName"> <div>{{ fullName }}</div> </div> </template> <script> export default { name: 'Vue2LearnHelloWorld', props: ['title'], data() { return { firstName: '', lastName: '', fullName: '' }; }, watch: { firstName(newval) { console.log('firstName变化了,这是最新的值:', newval); this.fullName = newval + '-' + this.lastName; }, lastName(newval) { console.log('lastName变化了,这是最新的值:', newval); this.fullName = this.firstName + '-' + newval; } }, }; </script>
从上面这个例子中我们可以看出:
1. computed能完成的功能,watch都可以完成
2. watch能完成的功能,computed不一定能完成。例如: watch可以进行异步操作(setTimeout, ajax, promise)
3. 所有能被vue管理的函数,最好写成普通函数,这样this才是vm或组件实例对象
4. 所有不被vue管理的函数(定时器的回调函数,ajax的回调函数,promise回调函数),最好写成箭头函数,这样this才是vm或组件实例对象