目录
3.2 watch函数和watchEffect 函数举例说明:
Vue.js 2.x 和 3.x 版本中的
watch
函数在使用方式和部分细节上有所不同。下面分别介绍两个版本的watch
函数的区别以及 Vue.js 3.x 版本中需要注意的点。
一、Vue.js 2.x 中的 watch 函数
在 Vue.js 2.x 版本中,watch
函数用于监听数据的变化,并在数据变化时触发对应的回调函数。watch
函数有以下常见用法:
监听某个属性变化:
export default {
data () {
return {
count: 0
}
},
watch: {
count (newVal, oldVal) {
console.log(`count 由 ${oldVal} 变为 ${newVal}`);
}
}
}
监听多个属性变化:
export default {
data () {
return {
message: '',
count: 0
}
},
watch: {
message (newVal, oldVal) {
console.log(`message 由 ${oldVal} 变为 ${newVal}`);
},
count (newVal, oldVal) {
console.log(`count 由 ${oldVal} 变为 ${newVal}`);
}
}
}
监听嵌套属性变化:
export default {
data () {
return {
user: {
name: '',
age: 0
}
}
},
watch: {
'user.name' (newVal, oldVal) {
console.log(`name 由 ${oldVal} 变为 ${newVal}`);
},
'user.age' (newVal, oldVal) {
console.log(`age 由 ${oldVal} 变为 ${newVal}`);
}
}
}
在监听属性变化的同时执行某些动作:
export default {
data () {
return {
count: 0
}
},
watch: {
count (newVal, oldVal) {
console.log(`count 由 ${oldVal} 变为 ${newVal}`);
this.doSomething();
}
},
methods: {
doSomething () {
// 在 count 变化的同时执行一些操作
}
}
}
二、Vue.js 3.x 中的 watch 函数
在 Vue.js 3.x 版本中,watch
函数在使用方式上和 2.x 版本有所不同。Vue.js 3.x 通过 watchEffect()
和 watch()
函数来替代 Vue.js 2.x 中的 watch
函数。下面是 Vue.js 3.x 的 watch
函数的一些特性和注意点:
2.1 监视reactive定义的响应式数据
- 监视
reactive
定义的响应式数据时:oldValue
无法正确获取、强制开启了深度监视(deep
配置失效)
watch(person,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
},{immediate:true,deep:false}) //此处的deep配置不再奏效
- 监视reactive定义的响应式数据中的某个属性
//情况四:监视reactive定义的响应式数据中的某个属性
watch(()=>person.job,(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{immediate:true,deep:true})
- 监视reactive定义的响应式数据中的某些属性
//情况五:监视reactive定义的响应式数据中的某些属性
watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{immediate:true,deep:true})
- 特殊情况(有三层结构或者更多层结构)
//特殊情况 job下面还有更深层次
watch(()=>person.job,(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{deep:true}) //此处由于监视的是reactive中定义的对象中的某个属性,所以deep配置有效
2.2 监视ref定义的响应式数据
- 监视ref定义的响应式数据
//情况一:监视ref定义的响应式数据
watch(sum,(newValue,oldValue)=>{
console.log('sum变化了',newValue,oldValue)
},{immediate:true})
- 如果用ref定义了一个对象
watch(person.value,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
})
或者这样:
watch(person,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
},{deep: true})
- 监视多个ref定义的响应式数据
//情况二:监视多个ref定义的响应式数据
watch([sum,msg],(newValue,oldValue)=>{
console.log('sum或msg变化了',newValue,oldValue)
})
三、watchEffect
函数
3.1 watch和watchEffect
-
watch
的套路是:既要指明监视的属性,也要指明监视的回调。 -
watchEffect
的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。 -
watchEffect
有点像computed
:
- 但
computed
注重的计算出来的值(回调函数的返回值),所以必须要写返回值。 - 而
watchEffect
更注重的是过程(回调函数的函数体),所以不用写返回值。
//watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。
watchEffect(()=>{
const a = sum.value
const b = person.age
console.log('watchEffect配置的回调执行了')
})
3.2 watch函数和watchEffect 函数举例说明:
侦听器的回调使用与源完全相同的响应式状态是很常见的。例如下面的代码,在每当
todoId
的引用发生变化时使用侦听器来加载一个远程资源:
const todoId = ref(1)
const data = ref(null)
watch(todoId, async () => {
const response = await fetch(
`https://jsonplaceholder.typicode.com/todos/${todoId.value}`
)
data.value = await response.json()
}, { immediate: true })
特别是注意侦听器是如何两次使用 todoId
的,一次是作为源,另一次是在回调中。
我们可以用 watchEffect 函数 来简化上面的代码。watchEffect()
允许我们自动跟踪回调的响应式依赖。上面的侦听器可以重写为:
watchEffect(async () => {
const response = await fetch(
`https://jsonplaceholder.typicode.com/todos/${todoId.value}`
)
data.value = await response.json()
})
这个例子中,回调会立即执行,不需要指定 immediate: true
。在执行期间,它会自动追踪 todoId.value
作为依赖(和计算属性类似)。每当 todoId.value
变化时,回调会再次执行。有了 watchEffect()
,我们不再需要明确传递 todoId
作为源值。
对于这种只有一个依赖项的例子来说,watchEffect()
的好处相对较小。但是对于有多个依赖项的侦听器来说,使用 watchEffect()
可以消除手动维护依赖列表的负担。此外,如果你需要侦听一个嵌套数据结构中的几个属性,watchEffect()
可能会比深度侦听器更有效,因为它将只跟踪回调中被使用到的属性,而不是递归地跟踪所有的属性。
3.3 watch
vs. watchEffect
watch
和 watchEffect
都能响应式地执行有副作用的回调。它们之间的主要区别是追踪响应式依赖的方式:
-
watch
只追踪明确侦听的数据源。它不会追踪任何在回调中访问到的东西。另外,仅在数据源确实改变时才会触发回调。watch
会避免在发生副作用时追踪依赖,因此,我们能更加精确地控制回调函数的触发时机。 -
watchEffect
,则会在副作用发生期间追踪依赖。它会在同步执行过程中,自动追踪所有能访问到的响应式属性。这更方便,而且代码往往更简洁,但有时其响应性依赖关系会不那么明确。