Vue 组件中5种Watch方式的使用
解释
watch是一个对象,这个对象的键是需要观察的表达式,值可以是直接方法、方法名、包含选项的对象等等,Vue实例会在实例化时调用$watch()
, 遍历watch对象的每一个属性,并且观察。
注意,本文不会阐述watch对象的具体实现源码,只是介绍watch对象键值的五种使用方式。
格式:
watch {
{ [key: string]: string | Function | Object | Array }
}
使用方式:
最直接的,直接用方法作为回调函数(或者说作为值)。
// 我们用vue的v-model指令来验证下watch对象的功能 <div> <p>{{msg}}</p> <input v-model="msg"> </div>
// pattern1 directly method value watch { // msg1 为表达式, function(oldVal, newVal)为匿名函数,作为回调函数 msg1: function (newVal, oldVal) { console.log("oldVal is: " + oldVal + " newVal is: " + newVal); } }
在双向绑定输入框输入一些值后,看console里watch对象的效果:
// 初始值为init,输入init1之后的console输出 oldVal is: init newVal is: init1
注意,回调函数的第一个参数是新的值,第二个是旧的值。
函数名作为值
// 同样用v-model验证效果 <div> <p>{{msg2}}</p> <input v-model="msg2"> </div>
// pattern 2 use function name as value watch { msg2: "methodway" } methods: { methodway (newVal, oldVal) { console.log("oldVal is: " + oldVal + " newVal is: " + newVal); } }
console输出:
// 初始值为init,输入init1之后的console输出 oldVal is: init newVal is: init1
观察键为对象/数组时,需要追加选项deep
当我们的被观察者是一个对象/数组的时候,我们改变了对象内部属性的值,用通常的watch方式是捕捉不到的。因为对于数组、对象本身来说,它并没有改变。这个时候需要加上选项
deep: true
<div> <p>{{msg3.attr1}}</p> <input v-model="msg3.attr1"> </div>
如果使用通常方式,改变了msg3的attr1属性值,watch并不会响应。需要加上deep选项:
watch { msg3: { handler: function (newVal, oldVal) { console.log("oldVal is: " + oldVal + " newVal is: " + newVal); }, // 加上这个选项之后,不论被嵌套得多深,被观察的对象的property一旦改变都会响应 deep:true } }
但是在这里的一个输出会有一个问题,虽然你能捕捉到对象的变更,但是你会发现oldVal和newVal是一样的,console输出:
// 对象的回调函数种,oldVal和newVal是一致的 oldVal is: {"attr1":"123","attr2":"2"} newVal is: {"attr1":"123","attr2":"2"}
也就是说,虽然我们能捕捉到变化,但是从watch对象里面的回调来说,我们无法准确抓取到变化的属性。如果想做到这点,我们可以单独观察对象的某个属性
msg3.attr1
或者使用computed
做中间层来观察。// computed做中间层,注意,并不是非要这样多写一层进行观察,可以直接观察属性 computed: { msg3attr() { return this.msg3.attr1; } } watch { msg3attr: function(newVal, oldVal) { console.log("oldVal is: " + oldVal + " newVal is: " + newVal); } }
这样就能观察到属性值的变化:
oldVal is: "12" newVal is: "123"
实例化后立刻回调
我们有时候会有要求Vue对象实例化后,立刻回调某一个Watch对象的键值。这个时候只需要加上一个选项
immediate: true
即可<div> <p>{{msg4}}</p> <input v-model="msg4"> </div>
watch { msg4: { handler(newVal, oldVal) { console.log("this should be called immediately."); }, // 加上immediate选项后,实例化后立刻回调一次 immediate:true }, }
console输出:
// 注意,我们并没有改变input的值,实例化之后立刻进行了回调 this should be called immediately.
回调函数数组
如果我们有多个回调函数需要执行,我们可以将Watch的值赋值为一个数组,数组内的函数将被逐一调用。
<div> <p>{{msg5}}</p> <input v-model="msg5"> </div>
watch { msg5: [ "methodchain1", function methodchain2(oldVal,newVal) { console.log("second method"); }, { handler(newVal, oldVal) { console.log("third method") },deep:true } ] }, methods: { methodchain1(newVal, oldVal) { console.log("first method"); } }
当msg5变更之后,console的输出:
// 回调函数被逐一调用 first method second method third method
值得一提的是,watch对象中,有时候键可以省略,我们用键的名字直接用作回调函数的名称,同样能正常观察到表达式的变化。
<div> <p>{{msg}}</p> <input v-model="msg"> </div>
watch { // 直接用表达式作为回调函数名称,效果一致 msg(newVal, oldVal) { console.log("oldVal is: " + oldVal + " newVal is: " + newVal); } }
console输出:
oldVal is: init newVal is: 1
需要特别注意的是,Watch对象中的回调函数不应该用箭头函数进行定义,它将导致上下文的混乱,this将指向错误的上下文。
以上为回调函数在组件中的五种使用方法,欢迎点赞、评论、收藏。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。