【Vue3】的watch,watchEffect侦听器分析

前提条件

vue3版本 vue v3.4.30

代码地址: https://cdn.bootcdn.net/ajax/libs/vue/3.4.30/vue.global.js

watch实现原理分析

 testComponet组件定义 

    在组件中定义了一个watch

var testComponet={
         name:"test-component",
         props: {
            testpmsg1: String,
            onPutinfo:Function,
            staticprop: String,
            bindproptest: String
         },
         data:function(){
            return {
               cmsg:"shengbinqian",
               cdata:"zhongguoren",
               url:"http://www.baidu.com"
            }
         },
         watch: {
            cmsg:function(newValue,oldValue){
               console.log("cmsg changed: ",oldValue,newValue);
            }
         },
         methods: {
            testdata1:function(str){
               console.log("testdata-"+str);
               this.$emit("chanage","你好我是子组件信息chanage");
            },
            testdata2:function(str){
               this.$emit("putinfo","你好我是子组件信息putinfo");
            }
         },
         template:`<div class='border:solid 1px red'>
                     <div>我是子组件testComponent---{
  {cmsg}}----bindproptest: {
  {bindproptest}}</div> 
                     <div><slot name="other" :url="url"></slot></div>
                     <div><button @click="testdata1" >chanageEmit</button></div> 
                     <div><button @click="testdata2" >putinfoEmit</button></div> 
                  </div>`,
         setup:function(props,ctx){
            let data={tname:"qianqian"};
            //如果父组件的模版定义中,设置了子组件的ref属性,那么在父组件中就可以获取到这个子组件的实例代理对象
            //但是如果子组件要想暴露它想暴露的数据,那么就可以适用expose()方法,如果设置了这个方法,那么父组件就只能访问这些expose的数据
            //起到一个屏蔽的作用
            //ctx.expose(data);
            console.log("testComponet-setup");
         }
      };

   在testComponet组件定义对象中定义了一个 watch,用于侦听cmsg数据。watch要实现的效果就是当cmsg变化时,会触发下面这个函数的执行。

      cmsg:function(newValue,oldValue){
               console.log("cmsg changed: ",oldValue,newValue);
       }

      更细致的说就是 cmsg响应式数据的deps(用于保存响应数据所有的副作用对象ReactiveEffect) 收集了一个副作用对象 ReactiveEffect ,然后这个对象(ReactiveEffect  )的scheduler 属性封装了上面那个响应函数(cmsg:function(newValue,oldValue)),那么有个问题是? 这个依赖关系是在什么时候收集的呢?  要收集依赖,肯定是要 触发cmsg 响应式数据的 get方法,然后这个代理方法就会有收集依赖的代码。

     分析:

      由于组件定义对象的watch: {}  会在applyOptions方法中进行解析,在这个方法中会触发createrWatcher方法,然后在这个方法中会把这个cmsg的key 封装成一个getter方法,getter方法的内容就是()=>publicThis[key(cmsg)],这个publicThis就是intance.proxy对象,是一个代理,在getter拦截方法中会收集依赖,那么就要在合适的时候触发这个方法(getter)执行就可以收集依赖(就是收集副作用对象ReactiveEffect),同时把上面定义的响应函数封装到ReactiveEffect对象中的scheduler 属性中就可以,同时ReactiveEffect 创建是把fn属性设置为getter方法,然后vue3会在doWatch方法中主动触发一次ReactiveEffect.run()方法,在这个run方法中就会执行fn,也就是getter方法,那么这样就把依赖收集成功了。

 //applyOptions中关键代码

      if (watchOptions) {
        ///侦听器 也是
        for (const key in watchOptions) { 

          //循环处理每个定义的watch数据
          createWatcher(watchOptions[key], ctx, publicThis, key);
        }
      }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值