1. computed
计算属性
作用:根据已有数据计算出新数据(和Vue2
中的computed
作用一致)。
2. watch
监视与watchEffect
1. watch
- 作用:监视数据的变化(和
Vue2
的watch
作用一致) - 特点:
Vue3
中的watch
只能监视以下4种数据:
ref
定义的数据reactive
定义的数据- 函数返回一个值(
getter
函数)- 一个包含上述内容的数组
我们在Vue3中使用watch的时候,通常会遇到以下几种情况:
- 情况一
监视ref
定义的【基本类型】数据:直接写数据名即可,监视的是其value
值的改变
<template>
<div>
<h1>情况一:监视【ref】定义的【基本类型】数据</h1>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<button @click="changeName">修改姓名</button>
<button @click="changeAge">修改年龄</button>
</div>
</template>
<script lang="ts" setup name="Person234">
import {ref, watch} from 'vue'
let name = ref('张三')
let age = ref(0)
function changeName(){
name.value += '~'
}
function changeAge(){
age.value += 1
}
watch(name, (nv, oldv)=>{
console.log('名字变了', nv, oldv)
})
// 监视,情况一:监视【ref】定义的【基本类型】数据
// 返回一个函数,当年龄等于5以后,停止监视,即调用返回函数即可
const stopWatch = watch(age, (nv, oldv)=>{
console.log('年龄变了', nv, oldv)
if(nv === 5){
stopWatch()
}
})
// 监视两个数据
// watch([name, age], (nv, oldv)=>{
// console.log('数据变了', nv, oldv)
// })
</script>
- 情况二
监视ref
定义的【对象类型】数据:直接写数据名,监视的是对象的【地址值】,若想监视对象内部的数据,要手动开启深度监视
注意:
- 若修改的是ref定义的对象中的属性,newValue和oldValue都是新值,因为它们是同一个对象
- 若修改整个ref定义的对象,newValue是新值,oldValue是旧值,因为不是同一个对象了
<template>
<div>
<h1>情况二:监视【ref】定义的【对象类型】数据</h1>
<h2>姓名:{{ person.name }}</h2>
<h2>年龄:{{ person.age }}</h2>
<button @click="changeName">修改姓名</button>
<button @click="changeAge">修改年龄</button>
<button @click="changePerson">修改人</button>
</div>
</template>
<script lang="ts" setup name="Person234">
import {ref, watch} from 'vue'
let person = ref({
name: '张三',
age: 19
})
function changeName(){
person.value.name += '~'
}
function changeAge(){
person.value.age += 1
}
function changePerson(){
person.value = { name: '李四', age: 90}
}
/* 监视,情况二:监视【ref】定义的【对象类型】数据,监视的是对象的地址值,若想监视对象内部的属性,需要收到开启深度监视
watch的第一个参数是:被监视的数据
watch的第二个参数是:监视的回调
watch的第三个参数是:配置对象(deep,immediate等等..)
*/
watch(person, (nv, oldv)=>{
console.log('名字变了', nv, oldv)
}, {deep:true, immediate: true})
</script>
- 情况三
监视reactive
定义的【对象类型】数据, 默认开启深度监视
<template>
<div>
<h1>情况三:监视【reactive】定义的【对象类型】数据</h1>
<h2>姓名:{{ person.name }}</h2>
<h2>年龄:{{ person.age }}</h2>
<button @click="changeName">修改姓名</button>
<button @click="changeAge">修改年龄</button>
<button @click="changePerson">修改人</button>
</div>
</template>
<script lang="ts" setup name="Person234">
import {reactive, watch} from 'vue'
let person = reactive({
name: '张三',
age: 19
})
function changeName(){
person.name += '~'
}
function changeAge(){
person.age += 1
}
function changePerson(){
person = Object.assign(person, { name: '李四', age: 90})
}
// 监视,情况三:监视【reactive】定义的【对象类型】数据,且默认是开启深度监视的
watch(person, (nv, oldv)=>{
console.log('名字变了', nv, oldv)
})
</script>
- 情况四
监视ref
或reactive
定义的【对象类型】数据的某个属性, 注意如下:
- 若该属性值不是【对象类型】,需写成函数形式
- 若该属性值是【对象类型】,可直接编写,也可以写成函数,建议写成函数
结论:监视的要是对象里的属性,那么最后写函数式,注意点:若是对象监视的是地址值,需要关注对象内部,需要手动开启深度监视
<template>
<div>
<h1>情况三:监视【reactive】定义的【对象类型】数据</h1>
<h2>姓名:{{ person.name }}</h2>
<h2>年龄:{{ person.age }}</h2>
<h2>第一量车:{{ person.car.c1 }}</h2>
<h2>第二量车:{{ person.car.c2 }}</h2>
<h2>车信息:{{ person.car.c1 }} - {{ person.car.c2 }}</h2>
<button @click="changeName">修改姓名</button>
<button @click="changeAge">修改年龄</button>
<button @click="changeC1">修改第一量车</button>
<button @click="changeC2">修改第二量车</button>
<button @click="changeCar">修改车</button>
</div>
</template>
<script lang="ts" setup name="Person234">
import {reactive, watch} from 'vue'
let person = reactive({
name: '张三',
age: 19,
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: '长安'}
}
// 监视,情况四:若该属性值不是【对象类型】,需写成函数形式
watch(()=> person.name, (nv, oldv)=>{
console.log('名字变了', nv, oldv)
})
// 监视,情况四:若该属性值是【对象类型】,可以直接编写
// 因为reactive定义的响应式对象person,所以car也是响应式对象,那么监视person.car就相当于reactive定义的一个car,默认开启深度监视,当修改c1和c2的时候,会监视到,但是当修改整个car,就相当于car的指针换了地址,原对象不变,所以changeCar不会触发监视,所以建议写成函数
// watch(person.car, (nv, oldv)=>{
// console.log('车变了', nv, oldv)
// })
// 监视,情况四:若该属性值是【对象类型】,建议写成函数
// 函数返回值是car的空间地址,对空间地址进行监视,则修改car的指针,会触发,但是内部属性变化,不会触发, 需要手动开启深度监听
watch(()=>person.car, (nv, oldv)=>{
console.log('车变了', nv, oldv)
},{ deep: true})
</script>
- 情况五
监视上述的多个数据
// watch([()=>person.name, ()=>person.car], (nv)=>{
// console.log('车变了', nv)
// },{ deep: true})
// 或者
watch([()=>person.name, person.car], (nv)=>{
console.log('车变了', nv)
},{ deep: true})
2. watchEffect
- 官网:立即运行一个函数,同时响应式的追踪其依赖,并在依赖更改时重新执行该函数
watch
对比watchEffect
- 都能监听响应式数据的变化,不同的是监听数据变化的方式不同
- watch:要明确指出监视的数据
- watchEffect: 不用明确指出监视的数据(函数中用到哪些属性,那就监视哪些属性)
- 示例代码:
<template>
<div>
<h1>当温度高于60或者高度高于20,调取接口</h1>
<h2>温度:{{ temp }}</h2>
<h2>高度:{{ height }}</h2>
<button @click="changeTemp">修改温度</button>
<button @click="changeHeight">修改高度</button>
</div>
</template>
<script lang="ts" setup name="Person234">
import {ref, watch, watchEffect} from 'vue'
let temp = ref(0)
let height = ref(0)
function changeTemp(){
temp.value += 10
}
function changeHeight(){
height.value += 10
}
// 使用watch,需要指定监视谁
// watch([temp, height], (nv)=>{
// const [temp, height] = nv
// if(temp >= 60 || height>=80){
// console.log('调取接口')
// }
// })
// 用watchEffect实现,不用
const stopWatch = watchEffect(()=>{
if(temp.value >= 60 || height.value >= 20){
console.log('调取接口', temp.value, height.value )
}
if(temp.value === 100 || height.value === 50){
console.log('停止监视', temp.value, height.value )
stopWatch()
}
})
</script>