1.6 vue 监听
在 Vue 2 中,watch
是一个非常有用的功能,它允许你监听数据的变化,并在数据发生变化时执行相应的逻辑。这对于需要在数据更新时触发复杂操作(比如异步请求、依赖多个状态的计算等)特别有用。
基本使用
你可以直接在组件的 watch
选项中定义监听器来监听某个属性的变化:
new Vue({el: '#demo',data() {return {message: 'Hello Vue!'}},watch: {message(newValue, oldValue) {console.log('newValue:', newValue);console.log('oldValue:', oldValue);}}
});
在这个例子中,每当 message
发生变化时,都会触发这个监听器,并打印新旧值。
监听对象的某个深层属性
方法1:使用函数作为监听器(推荐)
这是最常用和最直接的方法。将 watch
的键设置为一个函数,该函数返回你想要监听的深层属性的值。
new Vue({el: '#app',data() {return {user: {name: 'John Doe',age: 30}};},watch: {// ✅ 正确:使用函数返回要监听的值'user.name'(newVal, oldVal) {console.log(`Name changed from "${oldVal}" to "${newVal}"`);}// 或者写成函数形式(等效)//() => this.user.name: function(newVal, oldVal) {// console.log(`Name changed from "${oldVal}" to "${newVal}"`);//}}
});
- 注意:Vue 2 的
watch
确实支持使用'user.name'
这种字符串路径作为键,但这是一种特殊的语法糖,它内部会将其转换为一个访问路径的函数。虽然这种写法在实践中被广泛使用且有效,但严格来说,它依赖于 Vue 的内部实现。
方法 2:计算属性 (computed
) + watch
创建一个计算属性来提取你关心的深层属性,然后监听这个计算属性。
new Vue({el: '#app',data() {return {user: {name: 'John Doe',age: 30}};},computed: {// ✅ 计算属性返回 user.nameuserName() {return this.user.name;}},watch: {// ✅ 监听计算属性userName(newVal, oldVal) {console.log(`Name changed from "${oldVal}" to "${newVal}"`);}}
});
优点:逻辑清晰,性能好(只在 user.name
真正变化时触发)。 缺点:代码稍显冗余,需要额外定义一个计算属性。
总结
- 直接在
watch
选项中使用'user.name'
字符串路径,期望 Vue 自动解析,这种理解是不准确的。虽然 Vue 2 实现了这种语法糖,但它不是通过查找名为user.name
的属性实现的。 - 正确理解:Vue 2 的
watch
通过函数或特殊的路径解析机制来监听深层属性。 - 推荐方法:
- 函数方式:
() => this.user.name
(最清晰)。 - 计算属性方式:结合
computed
使用,逻辑分离,性能好。 - 深度监听:当需要监听对象多个属性时使用。
- 函数方式:
深度监听
如果你需要监听一个对象内部的变化,可以使用 deep: true
来启用深度监听:
new Vue({el: '#demo',data() {return {userProfile: {name: 'John Doe',age: 30}}},watch: {userProfile: {handler(newValue, oldValue) {console.log('userProfile changed');},deep: true}}
});
注意,由于 JavaScript 对象引用的问题,在深度监听回调函数中,newValue
和 oldValue
可能会指向同一个对象。
立即执行
有时候你可能希望在监听开始的时候立即执行一次监听器函数,这时可以使用 immediate: true
选项:
new Vue({el: '#demo',data() {return {question: ''}},watch: {question: {handler(newQuestion) {console.log('question changed:', newQuestion);},immediate: true}}
});
这会在监听器被创建时立即执行一次。
监听多个来源
你也可以在一个监听器里同时监听多个数据源:
new Vue({el: '#demo',data() {return {firstName: 'John',lastName: 'Doe'}},watch: {firstName(newVal) {this.fullName = newVal + ' ' + this.lastName;},lastName(newVal) {this.fullName = this.firstName + ' ' + newVal;}}
});
或者,如果你想在一个监听器内处理多个数据源,可以通过监听一个计算属性的方式来实现:
new Vue({el: '#demo',data() {return {firstName: 'John',lastName: 'Doe'}},computed: {fullName() {return this.firstName + ' ' + this.lastName;}},watch: {fullName: function() {console.log('fullName has changed');}}
});
使用 $watch
方法
除了在组件选项中定义监听器外,Vue 还提供了一个实例方法 $watch
,可以在组件生命周期内的任何时刻动态地添加监听器:
this.$watch('message', function(newValue, oldValue) {console.log(newValue, oldValue);
});
$watch
返回一个取消监听的函数,调用它可以停止监听:
var unwatch = this.$watch('message', function() { /* ... */ });
// 之后取消监听
unwatch();
$watch
和 watch
选项在 Vue.js 中都用于监听数据的变化,但它们的使用场景和一些特性有所不同。
$watch
方法
动态添加监听器:
$watch
是一个实例方法,允许你在组件创建后的任何时间点动态地添加监听器。这为开发者提供了更大的灵活性,尤其是在需要根据运行时条件来决定是否监听某些数据变化的情况下。返回值:调用
$watch
方法会返回一个取消监听的函数。你可以调用这个函数来停止监听。这对于需要手动管理监听器生命周期的情况特别有用。// 动态添加监听器 var unwatch = this.$watch('someData', function (newVal, oldVal) {console.log('someData changed from', oldVal, 'to', newVal); });// 在适当的时候停止监听 unwatch();
立即执行:与
watch
选项不同,$watch
默认不会在监听开始时立即执行一次监听回调(除非你设置了immediate: true
)。如果你希望在监听开始时也执行回调,可以传递第三个参数{ immediate: true }
给$watch
。
watch
选项
静态定义监听器:
watch
是 Vue 组件的一个选项,允许你在组件初始化时静态地定义监听器。这种方式更适合于那些在组件整个生命周期内都需要监听的数据变化。new Vue({el: '#demo',data() {return {message: 'Hello Vue!'}},watch: {message(newVal, oldVal) {console.log('message changed from', oldVal, 'to', newVal);}} });
配置更灵活:通过
watch
选项定义的监听器可以接受更多配置项,比如deep
(深度监听)和immediate
(立即执行)。这意味着你可以更容易地设置监听器的行为,而不需要额外的逻辑。new Vue({el: '#demo',data() {return {userProfile: {name: 'John Doe',age: 30}}},watch: {userProfile: {handler(newVal, oldVal) {console.log('userProfile changed');},deep: true,immediate: true}} });
总结
使用
watch
选项适合在组件初始化时静态定义监听器,并且当你可能需要利用其丰富的配置选项(如深度监听、立即执行等)时。- 使用
$watch
方法则更适合在运行时动态添加或移除监听器,尤其是当你需要控制监听器的生命周期或者基于某些条件来决定是否监听某个数据源时。
两者各有优势,选择哪一个取决于你的具体需求和应用场景。