1. 概述:
watch
(侦听器)是 Vue 提供的一个添加依赖变化时副作用扩展的 API。
我们可以给依赖 (data
, computed
, props
...) 添加侦听器,当这些依赖变化的时候可以实时执行一些副作用操作(e.g 表单提交,Ajax 请求)
2. watch 和 computed 的对比
2.1. 复习 computed 计算属性
- 关注点:模板
- 主要用来:抽离复用模板中复杂的逻辑和运算
- 特点: 当函数内部的依赖发生变化时, 重新计算结果调用
2.2. watch侦听器:
- 关注点:数据更新
- 主要用来:给数据添加更新监测 - 当数据更新时, 侦听器函数执行
- 特点: 在数据更新时, 需要完成什么逻辑
API 名称 | 关注点 | 主要用途 | 特点 |
---|---|---|---|
watch |
数据更新 | 给数据添加更新监测 - 当数据更新时, 侦听器函数执行 | 在数据更新时, 需要完成什么逻辑 |
computed |
模板 | 抽离复用模板中复杂的逻辑和运算,并渲染 | 当函数内部的依赖发生变化时, 重新计算结果调用 |
注意
- watch 侦听器默认首次是不会触发的(懒执行)
- watch 侦听器内设置的名字需要和数据的名字一致 (data, computed)
- 使用 watch 时,应该考虑的是给一个数据发生变化添加逻辑运算/回调函数添加副作用
3. 侦听器的语法
3.1. 基本使用
js
export default {
data() {
a: 1,
},
watch: {
a(newValue, oldValue) {
// ...
}
}
};
3.2. 用 . 分隔的路径注册侦听器
js
export default {
data() {
return {
some: {
nested: {
key: ''
}
},
};
},
watch: {
// 注意:只能是简单的路径,不支持表达式。
'some.nested.key'(newValue) {
// ...
}
}
};
3.3. 深层侦听器(deep)
watch 默认是浅层的:被侦听的属性,仅在被赋新值时,才会触发回调函数---而嵌套属性的变化不会触发。如果想侦听所有嵌套的变更,你需要深层侦听器:
深度侦听需要遍历被侦听对象中的所有嵌套的属性,当用于大型数据结构时,开销很大。因此请只在必要时才使用它,并且要留意性能。
js
export default {
watch: {
someObject: {
handler(newValue, oldValue) {
// 注意:在嵌套的变更中,
// 只要没有替换对象本身,
// 那么这里的 `newValue` 和 `oldValue` 相同
},
deep: true
}
}
}
3.4. 及时响应回调的侦听器(immediate)
- watch 默认是懒执行的:仅当数据源变化时,才会执行回调。但在某些场景中,我们希望在创建侦听器时,立即执行一遍回调。举例来说,我们想请求一些初始数据,然后在相关状态更改时重新请求数据。
- 我们可以用一个对象来声明侦听器,这个对象有 handler 方法和 immediate: true 选项,这样便能强制回调函数立即执行:
js
export default {
// ...
watch: {
question: {
handler(newQuestion) {
// 在组件实例创建时会立即调用
},
// 强制立即执行回调
immediate: true
}
}
// ...
}
4. 关于 watch 的一些补充点
4.1. watch 回调的触发时机
- 当你更改了响应式状态,它可能会同时触发 Vue 组件更新和侦听器回调。
- 默认情况下,用户创建的侦听器回调,都会在 Vue 组件更新之前被调用。这意味着你在侦听器回调中访问的 DOM 将是被 Vue 更新之前的状态。
- 如果想在侦听器回调中能访问被 Vue 更新之后的DOM,你需要指明 flush: 'post' 选项:
js
export default {
// ...
watch: {
key: {
handler() {},
flush: 'post'
}
}
}
4.2. this.$watch()
- 我们也可以使用组件实例的 $watch()方法来命令式地创建一个侦听器:
- 如果要在特定条件下设置一个侦听器,或者只侦听响应用户交互的内容,这方法很有用。它还允许你提前停止该侦听器。
js
export default {
created() {
this.$watch('question', (newQuestion) => {
// ...
})
}
}
4.3. unwatch - 侦听器停止
- 用 watch 选项或者 $watch() 实例方法声明的侦听器,会在宿主组件卸载时自动停止。因此,在大多数场景下,你无需关心怎么停止它。
- 在少数情况下,你的确需要在组件卸载之前就停止一个侦听器,这时可以调用 $watch() API 返回的函数。