在vue2中watch和computed这两个api对我们的帮助非常大,今天就说一说这两个Api
computed在vue3中以函数形式存在,传入一个对象,当里面的依赖被读取是,调用get函数,被修改时调用set函数
会返回一个ref对象
写一个经典案例
有个需求,给你一个姓,一个名,需要我们输出姓名,有的同学可能会直接采用字符串拼接,这样也可以,但是我们现在使用计算属性来试一下
set函数中所依赖的变量,一但被修改,便会立即执行set函数
get函数中所依赖的变量,只要被读取,就会执行get函数
这两个函数很简单,是vue2中响应式的原理
定义lastName,firstName,update更新函数,fullName为姓名
setup() {
const firstName = ref("李")
const lastName = ref("华")
const update = ()=>{
firstName.value = "孙"
}
let fullName = computed({
get(){
console.log("get"+'函数被调用');
return firstName.value+lastName.value
},
set(value){
console.log(“set函数被调用”);
}
})
return {
fullName,
update
}
}
fullName为计算属性,当get依赖被修改时,会立即执行get函数,并且返回新的数据,当fullname本身被修改时才会调用,set函数,这两个是有区别的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UZMaZeEW-1655790549116)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/52d0189e8e8b42a2877883187bce5ef2~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image?)] 我们可以看到,当我们打开网页时,会先执行一次get函数,然后修改fristName时会再执行一次get函数
在setup里面提供了watchEffect和watch两个api,这两个都可以做监听,区别我们后面总结
watchEffect自动收集依赖,初始化运行,返回值为stop一个函数,调用会停止监听
可以传入一个函数,第一次执行时自动收集获取依赖
这个函数不需要我们指定依赖,它会在第一次执行时,获取所对应的依赖
setup() {
const name = ref("scc")
const age = ref(18)
const update = ()=>{
age.value++
}
watchEffect(()=>{
console.log(age.value);
})
return {
name,
age,
update
}
}
定义一个name,age变量,update方法更新age,watchEffect监听age的值
我们可以看一下运行结果
可以看到,在刷新浏览器时,程序自动运行了一次,而且我们是可以监听到age值得变化的
先说一下setup中如何获取到dom元素,在vue2中,我们通过$refs获取dom元素,vue3中我们可以给dom元素一个ref属性,在setup中定义这个属性,并且传递出去,就可以通过这个属性获取到dom元素
setup() {
const root = ref(null)
const name = ref("scc")
watchEffect(()=>{
console.log(root.value);
})
return {
root
}
我们定义root,并且传递出去,给dom元素添加ref属性,看一下浏览器输出
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hDP7EQcQ-1655790549117)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f03b417d3116461a8ed10cbb8e6b4c49~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image?)] 此时我们是可以获取到dom元素的,但是它执行两次,大家发现了没有,第一次输出了null,第二次才是dom元素
这是为什么呢? 因为我们的watchEffect函数在dom没有刷新时初始化一次,dom挂载时又执行一次
如何避免这种情况,能不能只执行一次
是可以的,我们可以使用flush对象
在watchEffect后面可以配置一个flush对象,默认为pre,初始化运行,可以修改为post初始化不运行
我们尝试一下
setup() {
const root = ref(null)
watchEffect(()=>{
console.log(root.value);
},{
flush:"post"
})
return {
root
}
}
我们给watchEffect添加一个对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y2733LLa-1655790549118)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/21f7c00f0a034312827bd9c6c03fc9e6~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image?)] 此时watchEffect只执行了一次
watchEffect返回值为一个函数,执行此函数可以停止监听
setup() {
const name = ref("scc")
const age = ref(18)
const update = ()=>{
age.value++
}
const stop = watchEffect(()=>{
console.log(age.value);
if(age.value>25){
stop()
}
})
return {
name,
age,
update,
}
}
我们监听age属性,当他大于25时,就停止监听
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bvbTvCgx-1655790549118)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3fd279adcad7431b88f2bfe312e6981d~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image?)] 我们可以看到,当大于25时,页面还更新,但是已经不输出数据了
watch第一个参数是要监听的值,可以是ref对象,reactive对象,回调函数,第二个参数是回调函数,当监听的值发生变化,就会调用回调函数
setup() {
const info = reactive({age:18})
const update = ()=>{
console.log(info.age);
info.age++
}
watch(info,(newValue,oldValue)=>{
console.log(newValue+"------------------"+oldValue);
},{
deep:true
})
return{
info,
update
}
}
定义info,updat更改info.age,watch监听info
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L7HRtseL-1655790549118)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cb20ff4c06b3472da3eeafa070b41747~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image?)] 确实可以监听info但是,oldvalue,newvalue似乎和预期的不一样
这是因为newValue,oldValue也是reactive对象,想要变成值可以把reactive对象转换成对象()=>{return {…info}}
setup() {
const info = reactive({age:18,name:"scc"})
const update = ()=>{
console.log(info.age);
info.age++
}
watch(()=>({...info}),(newValue,oldValue)=>{
console.log(newValue,oldValue);
})
return{
info,
update
}
}
我们对info进行解构,对结构后的对象进行监听
可以看到,是没问题的
setup() {
const age = ref(18)
const update = ()=>{
console.log(age.value);
age.value++
}
watch(age,(newValue,oldValue)=>{
console.log(newValue,oldValue);
})
return{
age,
update
}
}
创建ref对象age,update更新age,watch监听age
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yALsRxdW-1655790549119)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e8e1ee824b9a452f97b25d0449f187f3~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image?)]
可以正常监听,显示内容
如果需要监听多个数据,可以传入一个数组
deep深度侦听默认为true,结构出来对象没有侦听,需要开启
immediate最开始是否运行
到此结束,明天接着更新