定义
watch 选项是一个对象,键是需要观察的表达式,值是对应回调函数。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。
用法
watch 对象里的 value 是对应的回调函数
data () {
return {
a: 1
}
},
watch: {
a: function (newVal, oldVal) {
console.log(newVal, oldVal)
// 2 1
}
},
created () {
this.a = 2
}
复制代码
当 a
的值被改变时,watch
对象中 a
所对应的函数会被调用,该函数接收两个参数,第一个为 a
的 new value,第二个为 a
的 old value。
value 也可以是方法名
data () {
return {
a: 1
}
},
watch: {
a: 'foo'
},
created () {
this.a = 2
},
methods: {
foo (newVal, oldVal) {
console.log(newVal, oldVal)
// 2 1
}
}
复制代码
当 a
的值被改变时,会直接触发 methods
里的 foo
方法,该方法同样接收新值和旧值两个参数。
深度监听
对象内部属性或方法发生改变,须使用深度监听模式才能监听到该对象的改变
data () {
return {
box: {
name: 'jordan'
}
}
},
watch: {
box: {
handler: function (newVal, oldVal) {
console.log(newVal.name, oldVal.name)
// kobe kobe
},
deep: true // 深度监听模式
}
},
created () {
this.box.name = 'kobe'
}
复制代码
运行代码会打印出 kobe kobe
,这是因为 box.name
的值更新之后, box
对象的内存地址仍然不变,newVal
和 oldVal
都指向该地址,值更新触发 handler
之后打印出两个更新之后的 name
,即 'kobe kobe'
。
如果去掉 deep: true
将无法监听到 box
的变化,除非直接给 this.box
赋值,改变 box
指针的指向,这种方式也能拿到 old value
和 new value
,对应 this.box
指针前后分别指向的 box
对象。
不使用深度监听时,可以直接监听 box.name
data () {
return {
box: {
name: 'jordan'
}
}
},
watch: {
'box.name': {
handler: function (newVal, oldVal) {
console.log(newVal, oldVal)
// kobe jordan
}
}
},
created () {
this.box.name = 'kobe'
}
复制代码
这时 box.name
又是一个简单值,所以输出 'kobe jordan'
。
数组的监听
data () {
return {
box: [1, 1, 1]
}
},
watch: {
box: {
handler: function () {
console.log('watch works')
}
}
},
created () {
this.box[0] = 2
this.box.length = 4
this.box.push(1) // watch works
this.box.splice(0, 1, 2) // watch works
}
复制代码
created
里使用了4种方式对 box
进行操作,第一种和第二种方式 watch
是监听不到的,即便使用深度监听模式也无法监听的到,可以参考下这里。
使用 immediate
data () {
return {
box: 1
}
},
watch: {
box: {
handler: function () {
console.log('watch works')
},
immediate: true
}
}
// watch works
复制代码
增加 immediate: true
选项,handler
会在侦听开始之后被立即调用,即便 box
的值没有改变。如果对 this.box
的值加以修改,便会输出两次 'watch works'
,一次是侦听开始的时候,一次是 box
的值被修改的时候。
watch 里的 value 可以是放在一个数组里面的多个 handler
data () {
return {
box: 1
}
},
watch: {
box: [
function foo (newVal, oldVal) {
console.log(newVal, oldVal)
// 2 1
},
function bar (newVal, oldVal) {
console.log(newVal, oldVal)
// 2 1
}
]
},
created () {
this.box = 2
}
复制代码
每一个 handler
都可以接收 new value
和 old value
两个参数,并且会按各自在数组中的顺序先后触发。当然下面的操作也能实现这样的场景。
data () {
return {
box: 1
}
},
watch: {
box: function (newVal, oldVal) {
this.foo(newVal, oldVal)
this.bar(newVal, oldVal)
}
},
created () {
this.box = 2
},
methods: {
foo (newVal, oldVal) {
console.log(newVal, oldVal)
},
bar (newVal, oldVal) {
console.log(newVal, oldVal)
}
}
复制代码
不应该使用箭头函数来定义 watcher 函数
data () {
return {
box: 1
}
},
watch: {
box: newVal => {
this.updateBox(newVal)
}
},
created () {
this.box = 2
},
methods: {
updateBox (newVal) {
this.box = newVal
}
}
复制代码
上面的例子会报错,是因为箭头函数绑定了父级作用域的上下文,所以 this 将不会指向 Vue 实例,也就没有 this.updateBox
这个方法,可以参考ES6箭头函数 this指向。