一.Vue3中computed用法
在Vue3的官方文档中,给予的computed的定义是这样的,computed()API接受一个getter函数,返回一个只读属性的响应式ref对象,ref通过暴露getter函数的返回值,它也可以接受一个带有get和set函数的对象来创建一个可写的ref对象。
1.1computed的只读性
通过computed得到的对象属性是只读的,得到的对象属性是不可修改的,在如下代码中我通过计算属性得到了一个人的全名,又定义了一个方法来修改通过computed得到的全名
一个人的姓:<input type="text" v-model="firstName"><br>
一个人的名:<input type="text" v-model="lastName"><br>
一个人的姓名:<span>{{ fullName }}</span>
<button @click="changefullName">点击修改全名</button>
let firstName=ref("张");
let lastName=ref("峻豪");
let fullName=computed(()=>{
return firstName.value+lastName.value;
})
function changefullName(){
fullName.value='余宇涵'
}
可以看到在上面的图片中,firstName和lastName是通过ref定义的,而fullName是通过computed得到的,fullName的值可以跟着firstName和lastName的值而改变,但是,如果我使用一个方法来直接改变fullName的值,就会出现如下结果:
控制台回给出一个警告,来告诉我们computed中的值为只读的,不可以直接修改。
1.2修改computed中的值:
如果我们在使用computed的时候想要修改computed的值,那我们就要用到一个computed中的set方法,具体如下代码所示:
let fullName=computed({
get:()=>{return firstName.value+lastName.value},
set:(val)=>{
console.log('set',val);
}
})
function changefullName(){
fullName.value='余宇涵'
}
在上述代码中,我调用了computed内部的get和set方法,get 是用来得到通过计算属性而得到的值,而使用set变 就可以修改通过计算属性而得到的值,当我调用changefullName方法,控制台就会显示这样:
1.3computed的其他特性:
computed它是根据他依赖的计算属性的变化而变化的,它和普通的计算函数不同,只要调用普通的计算函数,不管他的参数有没有变化,都会调用普通的计算函数,而computed不同,只有当他依赖的属性发生变化的时候,它才会执行功能。
二.Vue3中的watch方法:
在vue3的官方文档上给的watch的定义是这样的:侦听一个或者是多个响应式的数据源,并且在数据源发生变化的时候调用所给的回调函数。在实际应用watch的时候主要有以下五种情况:
2.1监视ref所定义的基本类型的数据:
这种情况就是当ref定义的基本类型的数据发生改变的时候,就会自动调用所给的回调函数,代码片段如下所示:
<p>监视ref定义的基本类型{{ sum }}</p>
<button @click="changeSum">点击改变sum的值</button>
function changeSum(){
sum.value+=10;
}
watch(sum,(newValue,oldValue)=>{
console.log('sum的值改变了',newValue,oldValue);
})
在上述代码片段中,watch的回调函数中接受newValue,oldValue两个值,当侦听到定义的sum对象发生改变式,就会调用回调函数,控制台输出如下所示:
2.2监视ref定义的对象类型的数据
如果使用watch监听ref定义的对象类型的数据,默认监听的是定义的整个对象,如果想要监听对象中的每一个属性,则要开启深度监听,代码体现如下:
<p>{{person.name}}</p>
<p>{{ person.age }}</p>
<button @click="changeName">修改我的名字</button>
<button @click="changeAge">修改我的年龄</button>
<button @click="changeAll">修改我的全部信息</button>
let person=ref({
name:'张峻豪',
age:16
})//定义的ref类型的对象
function changeName(){
person.value.name+='~'
}//修改名字
function changeAge(){
person.value.age+=1
}//修改年龄
function changeAll(){
person.value={name:"李菲",age:28}
}//修改整个对象的内容
watch(person,(newValue,oldValue)=>{
console.log('改变了person的内容',newValue,oldValue);
})//开启监视
在上述的代码片段中,我定义了一个ref类型的person对象,如果是默认监听的话,当我修改person对象里的name和age时,控制台不会打印,也就是说没有监听到对象中属性的变化,只有我修改整个对象的内容时,监听才起作用,控制台的结果如下:
如果我们想要监听到ref定义的对象类型中的每一个属性时,我们要开启深度监听,默认监听的只有在对象内存地址改变的情况下才起作用(也就是生成另一个新的对象),如果我们想要监听到person中的name和age,修改代码如下:
<p>{{person.name}}</p>
<p>{{ person.age }}</p>
<button @click="changeName">修改我的名字</button>
<button @click="changeAge">修改我的年龄</button>
<button @click="changeAll">修改我的全部信息</button>
let person=ref({
name:'张峻豪',
age:16
})//定义的ref类型的对象
function changeName(){
person.value.name+='~'
}//修改名字
function changeAge(){
person.value.age+=1
}//修改年龄
function changeAll(){
person.value={name:"李菲",age:28}
}//修改整个对象的内容
watch(person,(newValue,oldValue)=>{
console.log('改变了person的内容',newValue,oldValue);
},{deep:true})//开启深度监听
当我改变person中的name或者age时,控制台结果如下:
修改名字:
修改年龄:
2.3监听reactive所定义的对象类型:
当我们使用watch监听reactive定义的对象类型时,侦听器在底层默认开启了深度监听,所以能够监听到对象中每一个属性的值的变化,代码体现如下:
<p>{{person.name}}</p>
<p>{{ person.age }}</p>
<button @click="changeName">修改我的名字</button>
<button @click="changeAge">修改我的年龄</button>
<button @click="changeAll">修改我的全部信息</button>
let person=reactive({
name:'张峻豪',
age:16
})//定义一个reactive对象
function changeName(){
person.name+='~'
}//改变person的名字
function changeAge(){
person.age+=1
}//改变person的年龄
function changeAll(){
Object.assign(person,{name:"李菲",age:28})
}//使用对象中的方法改变整个对象的值
watch(person,(newValue,oldValue)=>{
console.log('改变了person对象的内容',newValue,oldValue);
})//开启监听
在上述代码中,当我改变person中的name和age时,侦听器能够监听到这两者的变化
控制台的结果显示监听到了person对象中属性的变化,但是,当我们整体改变person对象的内容时,会发现newValue和oldValue相同
出现上述情况是因为深度监听监听的是地址值变化的情况,而我改变对象的时候只是覆盖了原来对象的值,对象的地址值并没有改变,所以会出现上述情况。
2.4监听ref或者reactive对象中的非对象属性:
如果想要监视到ref或者是reactive对象中的非对象属性,就要使用get函数,先得到这个值,对得到的这个值进行监听,代码片段如下
<h2>{{ person.name }}</h2><br>
<h2>{{ person.age }}</h2><br>
<h2>{{ person.car.c1 }}</h2><br>
<h2>{{ person.car.c2 }}</h2><br>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="changeC1">修改第一个</button>
<button @click="changeC2">修改第二个</button>
<button @click="changeAll">修改全部</button>
let person=reactive({
name:"张峻豪",
age:16,
car:{
c1:'自行车',
c2:'电动车',
}
})
function changeName(){
person.name+='~'
}
function changeAge(){
person.age+=1
}
function changeC1(){
person.car.c1='宝马'
}
function changeC2(){
person.car.c2='奥迪'
}
function changeAll(){
person.car={c1:'红旗',c2:'迈巴赫'}
}
watch(()=>person.car,(newValue,oldValue)=>{
console.log('car的内容改变了',newValue,oldValue);
},{deep:true})
watch(()=>person.age,(newValue,oldValue)=>{
console.log('年龄改变了',newValue,oldValue);
})
控制台效果如下:
在上述代码中,在侦听器中使用了函数的形式(本质是get函数简写)来监听到对象中的非对象属性,当然了,对象属性也可以使用函数的形式来监听到 ,都使用函数形式来监听可以方便并且保险一些。
2.5监听多个属性:
当我们想使用监听器监听多个属性时,我们可以在监听器中将要监听的对象放在一个监听数组中,
代码体现如下:
watch([()=>person.age,person.car],(newValue,oldValue)=>{
console.log('观察改变的内容',newValue,oldValue);
},{deep:true})
把要监听的对象属性放在一个数组中,就可以监听多个对象属性了,由于car的类型时一个对象属性的,所以可以不使用函数的形式来监听。
三.watchEffect
当我们在实际应用时,会发现我们想要通过监听多个数据的变化来处理下一步逻辑,但是,当我们想要监听的数据比较多时,代码会比较冗余,所以,我们可以使用watchEffect来自动监听我们所要处理逻辑的数据
<h2>水位:{{ hei }}cm</h2>
<h2>水温:{{tem}}℃</h2>
<button @click="changeHei">改变水位</button>
<button @click="changeTem">改变水温</button>
let hei=ref(10)
let tem=ref(20)
function changeHei(){
hei.value+=10;
}
function changeTem(){
tem.value+=15;
}
watchEffect(()=>{
if(hei.value>30||tem.value>60){
console.log('向服务器发送数据',hei.value,tem.value);
}
})
其实,当我们使用watchEffect来监听数据时,就相当于开启来watch里的immediate,然后再根据下面的逻辑处理来监听所需要的数据,使用watchEffect时,在数据量比较多,并且逻辑所依赖的数据较多时,使代码更加简洁优雅。