computed
接受一个 getter 函数,返回一个只读的响应式 ref 对象。该 ref 通过 .value 暴露 getter 函数的返回值。它也可以接受一个带有 get 和 set 函数的对象来创建一个可写的 ref 对象。
创建一个只读的计算属性 ref:
<template><div class="person">姓名:<input type="text" v-model="fistname" ><br>年龄:<input type="text" v-model="lastname" ><br>信息:<span>{{ fullname }}</span></div>
</template><script lang="ts" setup name="Person">
import { ref, computed } from 'vue'const fistname = ref('xiao')
const lastname = ref('c')const fullname = computed(()=>{return fistname.value + "_" +lastname.value
})
</script>
创建一个可写的计算属性 ref:
<template><div class="person">姓名:<input type="text" v-model="fistname" ><br>年龄:<input type="text" v-model="lastname" ><br>切换:<button @click="changefullname">点击切换为xiao_b</button><br>信息:<span>{{ fullname }}</span></div>
</template><script lang="ts" setup name="Person">
import { ref, computed } from 'vue'const fistname = ref('xiao')
const lastname = ref('c')const fullname = computed({get(){return fistname.value + "_" +lastname.value},set(val){fistname.value=val.split("_")[0],lastname.value=val.split("_")[1]}
})function changefullname(){fullname.value="xiao_b"
}</script>
watch
侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。
监测数据变化
- 作用:监视数据的变化(和Vue2中的watch作用一致)
- 特点:Vue3中的watch只能监视以下四种数据:
ref定义的数据。
reactive定义的数据。
函数返回一个值(getter函数)。
一个包含上述内容的数组。
我们在Vue3中使用watch的时候,通常会遇到以下几种情况:
情况一
监视ref定义的【基本类型】数据:直接写数据名即可,监视的是其value值的改变。
代码如下:
<template><div><h1>情况一:监视【ref】定义的【基本类型】数据</h1><h2>当前求和为:{{ sum }}</h2><button @click="changeSum">点我sum+1</button></div>
</template>// 方法
<script setup lang="ts" name="Person">
import { ref, watch } from 'vue'
// 数据
const sum = ref(0)
// 函数
function changeSum () {sum.value += 1
}
// 监视,情况一:监视【ref】定义的【基本类型】数据
const stopWatch = watch(sum, (newVale, oldVale) => {console.log('sum变化了', newVale, oldVale)if (newVale >= 10) {stopWatch()}
})
</script>
效果:
情况二
监视ref定义的【对象类型】数据:直接写数据名,监视的是对象的【地址值】,若想监视对象内部的数据,要手动开启深度监视。
注意:
若修改的是
ref
定义的对象中的属性,newValue
和oldValue
都是新值,因为它们是同一个对象。若修改整个
ref
定义的对象,newValue
是新值,oldValue
是旧值,因为不是同一个对象了。
代码如下:
<template><div class="person"><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="Person">import {ref,watch} from 'vue'// 数据let person = ref({name:'张三',age:18})// 方法function changeName(){person.value.name += '~'}function changeAge(){person.value.age += 1}function changePerson(){person.value = {name:'李四',age:90}}/* 监视,情况一:监视【ref】定义的【对象类型】数据,监视的是对象的地址值,若想监视对象内部属性的变化,需要手动开启深度监视{deep:true}watch的第一个参数是:被监视的数据watch的第二个参数是:监视的回调watch的第三个参数是:配置对象(deep、immediate等等.....) */watch(person,(newValue,oldValue)=>{console.log('person变化了',newValue,oldValue)},{deep:true})</script>
情况三
监视reactive定义的【对象类型】数据,且默认开启了深度监视。
<template><div class="person"><h1>情况三:监视【reactive】定义的【对象类型】数据</h1><h2>姓名:{{ person.name }}</h2><h2>年龄:{{ person.age }}</h2><button @click="changeName">修改名字</button><button @click="changeAge">修改年龄</button><button @click="changePerson">修改整个人</button><hr><h2>测试:{{obj.a.b.c}}</h2><button @click="test">修改obj.a.b.c</button></div>
</template><script lang="ts" setup name="Person">import {reactive,watch} from 'vue'// 数据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)})
</script>情况四
监视ref或reactive定义的【对象类型】数据中的某个属性,注意点如下:
若该属性值不是【对象类型】,需要写成函数形式。
若该属性值是依然是【对象类型】,可直接编,也可写成函数,建议写成函数。
结论:监视的要是对象里的属性,那么最好写函数式,注意点:若是对象监视的是地址值,需要关注对象内部,需要手动开启深度监视。
<template><div class="person"><h1>情况四:监视【ref】或【reactive】定义的【对象类型】数据中的某个属性</h1><h2>姓名:{{ person.name }}</h2><h2>年龄:{{ person.age }}</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="Person">import {reactive,watch} from 'vue'// 数据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:'爱玛'}}// 监视,情况四:监视响应式对象中的某个属性,且该属性是基本类型的,要写成函数式/* watch(()=> person.name,(newValue,oldValue)=>{console.log('person.name变化了',newValue,oldValue)}) */// 监视,情况四:监视响应式对象中的某个属性,且该属性是对象类型的,可以直接写,也能写函数,更推荐写函数watch(()=>person.car,(newValue,oldValue)=>{console.log('person.car变化了',newValue,oldValue)},{deep:true})
</script>
情况五
监视上述的多个数据
<template><div class="person"><h1>情况五:监视上述的多个数据</h1><h2>姓名:{{ person.name }}</h2><h2>年龄:{{ person.age }}</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="Person">import {reactive,watch} from 'vue'// 数据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:'爱玛'}}// 监视,情况五:监视上述的多个数据watch([()=>person.name,person.car],(newValue,oldValue)=>{console.log('person.car变化了',newValue,oldValue)},{deep:true})</script>
watchEffect
官网:立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行该函数。
watch对比watchEffect
1. 都能监听响应式数据的变化,不同的是监听数据变化的方式不同
2. watch:要明确指出监视的数据
3. watchEffect:不用明确指出监视的数据(函数中用到哪些属性,那就监视哪些属性)。
示例代码:
<template><div class="person"><h1>需求:水温达到50℃,或水位达到20cm,则联系服务器</h1><h2 id="demotemp">水温:{{temp}}</h2><h2 id="demoheight">水位:{{height}}</h2><button @click="changePrice">水温+1</button><button @click="changeSum">水位+10</button></div>
</template><script lang="ts" setup name="Person">import {ref,watch,watchEffect} from 'vue'// 数据let temp = ref(0)let height = ref(0)// 方法function changePrice(){temp.value += 10}function changeSum(){height.value += 10}// 用watch实现,需要明确的指出要监视:temp、height// watch([temp,height],(value)=>{// // 从value中获取最新的temp值、height值// const [newTemp,newHeight] = value// // 室温达到50℃,或水位达到20cm,立刻联系服务器// if(newTemp >= 50 || newHeight >= 20){// console.log('联系服务器')// }// })// 用watchEffect实现,不用之处需要监视的参数const stopWtach = watchEffect(()=>{// 室温达到50℃,或水位达到20cm,立刻联系服务器if(temp.value >= 50){console.log(document.getElementById('demotemp')?.innerText)console.log('联系服务器')}if(height.value >= 20){console.log(document.getElementById('demoheight')?.innerText)console.log('联系服务器')}// 水温达到100,或水位达到50,取消监视if(temp.value === 100 || height.value === 50){console.log('清理了')stopWtach()}})
</script>