之前用过vue2中的watch监听,最近在学vue3,对比两个版本对于watch使用的不同之处做个总结,然后记录下vue3中watch中的具体使用方法和技巧
Vue 2 中,watch 选项接收一个对象,键是要观察的属性名,值是回调函数或者包含选项的对象。
Vue 3 中,watch 可以通过 watch 函数来实现,支持多种参数传递方式,更加灵活。
Vue 2 中,直接监听对象的某个属性变化时,如果对象的属性被添加或删除,不会触发监听。
Vue 3 中,使用 watch 函数并结合 deep 选项可以更方便地监听对象属性的深层次变化,包括属性的添加和删除。
Vue 2 中,要监听多个数据源需要分别配置多个 watch 选项。
Vue 3 中,可以在一个 watch 函数中同时监听多个数据源。
Vue 3 中停止监听的函数 watch,方便在组件卸载等场景中清除副作用
在vue3中 文档中有说明 watch可监听的类型有四种:
watch函数一共有三个参数
第一个参数是监听的的源,源可为上方的四种类型
第二个参数是回调函数,返回新值和旧值和vue2一样,还有第三个参数onCleanup函数。onCleanup可以用来注册清理回调,在下次侦听器执行前会被调用。
第三个参数 是配置项(非必填可选择)包含一下配置
<template>
<div>
<h1>姓名:{{ man }}</h1>
<button @click="changeName">改变姓名</button>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
let man = ref('帅哥')
function changeName(){
man.value += '~真帅'
}
// 这里直接写man就可以,不要写man.vue
watch(man,(newValue,oldValue) => {
console.log('改变了', newValue,oldValue)
})
</script>
watch函数返回一个用于停止监听的函数,执行这个返回函数就会停止watch的监视
<template>
<div>
<h1>计数:{{ num }}</h1>
<button @click="changeName">累加</button>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
let num = ref(0)
function changeName(){
num.value += 1
}
let stopWatch = watch(num,(newValue,oldValue) => {
console.log('改变了', newValue,oldValue)
// 当num 大于10的时候 停止监视
if(newValue > 10){
stopWatch()
}
})
</script>
定义ref的对象类型,watch监听默认情况下只监听这个对象的本身(存储地址),而对象内部的元素值变化不会触发监听
<template>
<div>
<h1>姓名:{{ man.name }}</h1>
<h1>年龄:{{ man.age }}</h1>
<button @click="changeName">改变姓名</button>
<button @click="changeAge">改变年龄</button>
<button @click="changeMan">改变人</button>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
let man = ref({
name: '帅哥',
age: 20,
})
function changeName() {
man.value.name += '~帅'
}
function changeAge() {
man.value.age += 1
}
function changeMan() {
man.value = {
name: '美女',
age: 18,
}
}
watch(man, (newValue, oldValue) => {
console.log('改变了', newValue, oldValue)
})
</script>
<style>
button {
margin: 10px;
}
</style>
如果也想要监听内部的元素值变化,可开启deep,但要注意的是,这时改变对象内部元素的时候 newValue, oldValue 是一样的都是新值,只有改变整个对象,才能拿到oldValue旧值
watch(man, (newValue, oldValue) => {
console.log('改变了', newValue, oldValue)
}, { deep: true})
未开启deep | 开启deep |
---|---|
如果只想监听对象中一个元素,例如只想监听name的变化,可以改为监听一个函数,函数返回这个对象的元素,但需要注意的是 这种写法改变整改对象(实例中的改变人方法)也会触发监听!
错误的写法,不能直接监听value,因为 它不属于watch可监听的四种类型,所以不支持
watch(man.value, (newValue, oldValue) => {
console.log('改变了', newValue, oldValue)
}, { deep: true })
// 默认只监听 man这个对象的地址,对象内部的元素值变化不会触发监听
watch(() => man.value.name, (newValue, oldValue) => {
console.log('改变了', newValue, oldValue)
}, { deep: true })
注意watch直接监听一个reactive是默认开启深度监听的,也就修改对象中任何一个值都会触发监听,且这种深度监听是不能关闭的。即便设置deep为false 也是无效的
当想修改整个reactive对象时,要注意,像以下这几种写法 都是错误的,这样会让man对象失去响应式
监听 reactive例子
<template>
<div>
<h1>姓名:{{ man.name }}</h1>
<h1>年龄:{{ man.age }}</h1>
<h1>我得第1部手机:{{ man.phones.phone1 }}</h1>
<h1>我得第2部手机:{{ man.phones.phone2 }}</h1>
<button @click="changeName">改变姓名</button>
<button @click="changeAge">改变年龄</button>
<button @click="changePhone1">改变第一部手机</button>
<button @click="changePhone2">改变第二部手机</button>
<button @click="changePhone">改变所有手机</button>
<button @click="changeMan">改变这个人</button>
</div>
</template>
<script setup>
import { reactive, watch } from 'vue'
let man = reactive({
name: '帅哥',
age: 20,
phones: {
phone1: '红米',
phone2: '苹果',
}
})
function changeName() {
man.name += '~帅'
}
function changeAge() {
man.age += 1
}
function changePhone1() {
man.phones.phone1 = '华为'
}
function changePhone2() {
man.phones.phone2 = '小米'
}
function changePhone() {
man.phones = {
phone1: 'vivo',
phone2: 'oppo',
}
}
function changeMan() {
// // 错误的写法 1 数据不生效,页面不相应,watch也不会触发
// man = reactive({
// name: '大神',
// age: 30,
// phones: {
// phone1: '诺基亚1',
// phone2: '诺基亚2',
// }
// })
// // 错误的写法 2 数据不生效,页面不相应,watch也不会触发
// man = {
// name: '大神',
// age: 30,
// phones: {
// phone1: '诺基亚1',
// phone2: '诺基亚2',
// }
// }
// // 错误的写法3 数据不生效,页面不相应,watch会触发,
// man.value = {
// name: '大神',
// age: 30,
// phones: {
// phone1: '诺基亚1',
// phone2: '诺基亚2',
// }
// }
// 正确的写法 watch响应 回调里的新旧值一样
Object.assign(man, {
name: '大神',
age: 30,
phones: {
phone1: '诺基亚1',
phone2: '诺基亚2',
}
})
}
watch(man, (newValue, oldValue) => {
console.log('改变了', newValue, oldValue)
})
</script>
<style>
button {
margin: 10px;
}
</style>
</script>
第一种情况
如果想要只监听man对象中的某一个元素,方法的话和上文中监听ref的方法一样,
把监听源换成一个函数,函数返回这个reactive对象的属性
错误的写法
watch(man.age, (newValue, oldValue) => {
console.log('改变了', newValue, oldValue)
})
正确的写法
watch(() => man.age, (newValue, oldValue) => {
console.log('改变了', newValue, oldValue)
})
第二种情况
如果想要只监听man对象中的多个元素,例如只想监听man的age和 phones 下的phone1
监视源就要改为一个数组,数据的元素为函数, 要注意的是此时的回调函数里返回的 newValue、oldVaule 也就只剩下监视的这两个值了
watch([() => man.age, () => man.phones.phone1], (newValue, oldValue) => {
console.log('改变了', newValue, oldValue)
})
第三种
只监听 age和 phones,这时候 phones 就不用函数了
watch([() => man.age, man.phones], (newValue, oldValue) => {
console.log('改变了', newValue, oldValue)
})
总结一句话就是,如果要监听对象里的某个属性,那监听资源就要写函数式
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。