vue3中watch监听的几种情况

一、监听ref创建的基本数据类型

watch的第一个参数直接写需要监听的数据名即可,监听的是其值的变化

js 复制代码
    <div>
      <h1>情况一:监视【ref】定义的【基本类型】数据</h1>
      <h2>当前求和为:{{ sum }}</h2>
      <el-button @click="changeSum">点我sum+1</el-button>
    </div>
    
    
    
// 数据
let sum = ref(0)
// 方法
function changeSum() {
  sum.value += 1
}
// 监视,情况一:监视【ref】定义的【基本类型】数据
const stopWatch = watch(sum, (newValue, oldValue) => {
  console.log('sum变化了', newValue, oldValue)
  if (newValue >= 10) {
    stopWatch()
  }
})

二、监听ref创建的对象类型

  1. watch监听person时,监听的是person的地址值,只有当person的引用地址发生变化时才能监听得到,当写成Object.assign(person.value, { name: '李四', age: 90, son: { age: 5 } })时依然监听不到
  2. 当开启deep: true时,无论修改person中的哪个参数,包括son对象,都能监听得到
js 复制代码
    <div>
      <h1>情况二:监视【ref】定义的【对象类型】数据</h1>
      <h2>姓名:{{ person.name }}</h2>
      <h2>年龄:{{ person.age }}</h2>
      <h2>儿子年龄:{{ person.son.age }}</h2>
      <el-button @click="changeName">修改名字</el-button>
      <el-button @click="changeAge">修改年龄</el-button>
      <el-button @click="changePerson">修改整个人</el-button>
      <el-button @click="changeSonAge">修改儿子年龄</el-button>
    </div>
    
// 数据
let person = ref({
  name: '张三',
  age: 18,
  son: { age: 5 }
})
// 方法
function changeName() {
  person.value.name += '~'
}
function changeAge() {
  person.value.age += 1
}
function changePerson() {
  person.value = { name: '李四', age: 90, son: { age: 5 } }
}
function changeSonAge() {
  person.value.son.age += 1
}
watch(
  person,
  (newValue, oldValue) => {
    console.log('person变化了', newValue, oldValue)
  },
  { deep: true }
)

三、监听reactive定义的对象类型数据,会默认开启深度监听

前面提到,如果是监听ref创建的对象类型数据,需要手动开启深度监听,而监听reactive创建的对象类型数据时,会自动开启深度监听

js 复制代码
    <div>
      <h1>情况三:监视【reactive】定义的【对象类型】数据</h1>
      <h2>姓名:{{ person.name }}</h2>
      <h2>年龄:{{ person.age }}</h2>
      <el-button @click="changeName">修改名字</el-button>
      <el-button @click="changeAge">修改年龄</el-button>
      <el-button @click="changePerson">修改整个人</el-button>
      <hr />
      <h2>测试:{{ obj.a.b.c }}</h2>
      <el-button @click="test">修改obj.a.b.c</el-button>
    </div>
    
// 数据
let person = reactive({ name: '张三', age: 18 })
let obj = reactive({ a: { b: { c: 666 } } })
// 方法
function changeName() {
  person.name += '~'
}
function changeAge() {
  person.age += 1
}
function changePerson() {
  Object.assign(person, { name: '李四', age: 80 })
}
function test() {
  obj.a.b.c += 888
}

// 监视,情况三:监视【reactive】定义的【对象类型】数据,且默认是开启深度监视的
watch(person, (newValue, oldValue) => {
  console.log('person变化了', newValue, oldValue)
})
watch(obj, (newValue, oldValue) => {
  console.log('Obj变化了', newValue, oldValue)
})

四、监听ref或reactive定义的对象类型中的某个属性

  1. 监听的是对象的基本类型数据,要写成函数形式
  2. 监听的是对象的对象类型数据,可以写成函数形式,也可以直接写
  3. 监听的是对象的对象类型数据,并且改变对象时改变了应用地址,例如person.car = { ... },就必须要写成函数形式
js 复制代码
    <div>
      <h1>情况四:监视【ref】或【reactive】定义的【对象类型】数据中的某个属性</h1>
      <h2>姓名:{{ person.name }}</h2>
      <h2>年龄:{{ person.age }}</h2>
      <h2>汽车:{{ person.car.c1 }}、{{ person.car.c2 }}</h2>
      <el-button @click="changeName">修改名字</el-button>
      <el-button @click="changeAge">修改年龄</el-button>
      <el-button @click="changeC1">修改第一台车</el-button>
      <el-button @click="changeC2">修改第二台车</el-button>
      <el-button @click="changeCar">修改整个车</el-button>
    </div>
    
// 数据
let person = reactive({ name: '张三', age: 18, car: { c1: '奔驰', c2: '宝马' } })
// 方法
function changeName() {
  person.name += '~'
}
function changeAge() {
  person.age += 1
}
function changeC1() {
  person.car.c1 = '奥迪'
}
function changeC2() {
  person.car.c2 = '大众'
}
function changeCar() {
  // person.car = { c1: '雅迪', c2: '爱玛' }
  Object.assign(person.car, { c1: '雅迪', c2: '爱玛' })
}
// 监视,情况四:监视响应式对象中的某个属性,且该属性是基本类型的,要写成函数式
watch(
  () => person.name,
  (newValue, oldValue) => {
    console.log('person.name变化了', newValue, oldValue)
  }
)
watch(
  () => person.car, // 如果使用 person.car = { ... } 必须要使用函数写法;如果使用Object.assign,可以直接写person.car
  (newValue, oldValue) => {
    console.log('person.car变化了', newValue, oldValue)
  },
  { deep: true }
)

如果需要监听多个数据,可以将2个watch合并为一个:

js 复制代码
watch(
  [() => person.name, () => person.car],
  (newValue, oldValue) => {
    console.log('person.car变化了', newValue, oldValue)
  },
  { deep: true }
)

总结:

  1. 监听ref创建的基本数据类型,必须直接写,不可以写成函数形式
  2. 监听ref创建的对象数据类型,可以直接写,也可以写成函数形式,需要开启deep: true
  3. 监听reactive创建的对象数据类型,必须直接写,不可以写成函数形式,默认开启了deep: true
  4. 监听ref或reactive创建的对象类型中的某个属性,该类型为基本数据类型,必须写成函数形式
  5. 监听ref或reactive创建的对象类型中的某个属性,该类型为对象数据类型,可以直接写,也可以写成函数形式,需要开启deep: true。如果想要监听引用地址变化,必须写成函数形式
序号 情况 是否使用函数写法 是否需要手动开启深度监听
1 监听ref创建的基本数据类型 否。必须直接写,不可以写成函数形式 否
2 监听ref创建的对象数据类型 皆可。可以直接写,也可以写成函数形式 是
3 监听reactive创建的对象数据类型 否。必须直接写,不可以写成函数形式 否。默认开启了深度监听
4 监听ref或reactive创建的对象类型中的某个属性,该类型为基本数据类型 是。必须写成函数形式 否
5 监听ref或reactive创建的对象类型中的某个属性,该类型为对象数据类型 皆可。可以直接写,也可以写成函数形式;如果想要监听引用地址变化,必须写成函数形式 是
相关推荐
修炼的dance12 分钟前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M19 分钟前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写21 分钟前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李22 分钟前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易36 分钟前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
风骏时光牛马1 小时前
前沿视界
前端
kyriewen1 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员
陈随易1 小时前
3000 万人在用的翻译插件,重写一遍就是一门生意
前端·后端·程序员
IT_陈寒1 小时前
Vue的这个响应式陷阱,差点让我加班到天亮
前端·人工智能·后端
Flynt3 小时前
别写拖拽行为,只声明"能拖到哪":UIST 最佳论文的拖拽方案我实测了
前端·svg·preact