Vue源码学习(十三):实现watch(一):方法,对象

好家伙,

 代码出了点bug,暂时只能实现这两种形式

 

完整代码已开源https://github.com/Fattiger4399/analytic-vue.git

Vue:watch的多种使用方法

watch有非常多种使用方式,我们要对其进行分类讨论处理

 

1.初始化:

//initState.js

if (opts.watch) {         initWatch(vm);     }

 

initWatch()方法

function initWatch(vm) {     //1 获取watch     let watch = vm.$options.watch     console.log(watch)     //2 遍历  { a,b,c}     for (let key in watch) {         //2.1获取 他的属性对应的值 (判断)         let handler = watch[key] //数组 ,对象 ,字符,函数         if (Array.isArray(handler)) {//数组  []             handler.forEach(item=>{                 createrWatcher(vm,key,item)              })         } else {//对象 ,字符,函数            //3创建一个方法来处理            createrWatcher(vm,key,handler)         }     } }

 

createrWatcher()

//格式化处理 //vm 实例 //exprOrfn key //hendler key对应的值 //options 自定义配置项 vue自己的为空,用户定义的才有 function createrWatcher(vm,exprOrfn,handler,options){    //3.1 处理handler    if(typeof handler ==='object'){        options = handler; //用户的配置项目        handler = handler.handler;//这个是一个函数    }    if(typeof handler ==='string'){// 'aa'        handler = vm[handler] //将实例行的方法作为 handler 方法代理和data 一样    }    //其他是 函数    //watch 最终处理 $watch 这个方法 //    console.log(vm,"||vm") //    console.log(exprOrfn,"||exprOrfn") //    console.log(handler,"||handler") //    console.log(options,"||options")     return vm.$watch(vm,exprOrfn,handler,options) }

 

原型上挂$watch方法

export function stateMixin(vm) {     console.log(vm,6666)     //列队 :1就是vue自己的nextTick  2用户自己的     vm.prototype.$nextTick = function (cb) { //nextTick: 数据更新之后获取到最新的DOM         //  console.log(cb)         nextTick(cb)     },     vm.prototype.$watch =function(Vue,exprOrfn,handler,options={}){ //上面格式化处理         //   console.log(exprOrfn,handler,options)           //实现watch 方法 就是new  watcher //渲染走 渲染watcher $watch 走 watcher  user false          //  watch 核心 watcher          let watcher = new Watcher(Vue,exprOrfn,handler,{...options,user:true})                     if(options.immediate){             handler.call(Vue) //如果有这个immediate 立即执行          }     }      }

 

 

2.watcher.js

watcher类

class Watcher {     //vm 实例     //exprOrfn vm._updata(vm._render())      constructor(vm, exprOrfn, cb, options) {         // 1.创建类第一步将选项放在实例上         this.vm = vm;         this.exprOrfn = exprOrfn;         this.cb = cb;         this.options = options;         // 2. 每一组件只有一个watcher 他是为标识         this.id = id++         this.user = !!options.user         // 3.判断表达式是不是一个函数         this.deps = []  //watcher 记录有多少dep 依赖         this.depsId = new Set()         if (typeof exprOrfn === 'function') {             this.getter = exprOrfn         }else{ //{a,b,c}  字符串 变成函数              this.getter =function(){ //属性 c.c.c               let path = exprOrfn.split('.')               let obj = vm               for(let i = 0;i<path.length;i++){                 obj  = obj[path[i]]               }               return obj //             }         }         // 4.执行渲染页面         this.value =  this.get() //保存watch 初始值      }     addDep(dep) {         //去重  判断一下 如果dep 相同我们是不用去处理的         let id = dep.id         //  console.log(dep.id)         if (!this.depsId.has(id)) {             this.deps.push(dep)             this.depsId.add(id)             //同时将watcher 放到 dep中             // console.log(666)             dep.addSub(this)          }         // 现在只需要记住  一个watcher 有多个dep,一个dep 有多个watcher         //为后面的 component      }     run() { //old new        let value =  this.get() //new        let oldValue = this.value //old        this.value = value        //执行 hendler (cb) 这个用户wathcer        if(this.user){         this.cb.call(this.vm,value,oldValue)        }     }     get() {         // Dep.target = watcher          pushTarget(this) //当前的实例添加       const value = this.getter()// 渲染页面  render()   with(wm){_v(msg,_s(name))} ,取值(执行get这个方法) 走劫持方法         popTarget(); //删除当前的实例 这两个方法放在 dep 中         return value     }     //问题:要把属性和watcher 绑定在一起   去html页面     // (1)是不是页面中调用的属性要和watcher 关联起来     //方法     //(1)创建一个dep 模块     updata() { //三次         //注意:不要数据更新后每次都调用 get 方法 ,get 方法回重新渲染         //缓存         // this.get() //重新渲染         queueWatcher(this)     } }

 

3.看看效果

<body>     <div id="app">{{a}}</div>     <script src='./dist/vue.js'></script>     <script>         let vm = new Vue({             el: "#app",             data: {                 a: 1,                 b:[1,2],                 c:{c:{c:100}}             },             methods:{                 aa(){                     console.log(2000)                 }             },             //watch 基本使用方式             //1 属性 :方法(函数)             //2 属性 :数组             //3 属性 :对象             //4 属性 :字符串             watch: {                   'c.c.c'(newValue,oldValue){                       console.log(newValue,oldValue,'||this isnewValue,oldValue from c.c.c')                   },                                  a:{                     handler(){ //                         console.log('a数据更新')                     },                    immediate:true                                      },                 // a:'aa',             }         })         vm.a = 100         // vm.b[1] = 2         console.log(vm.c.c.c=2000)     </script> </body>

 

Vue源码学习(十三):实现watch(一):方法,对象

 

 

发表评论

评论已关闭。

相关文章