• 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){
                    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.看看效果

    复制代码
    
        
    id="app">{{a}}
    复制代码

     

     

     

  • 相关阅读:
    【Java 进阶篇】Java Tomcat 入门指南
    Nginx + Tomcat 搭建负载均衡、动态分离
    代码随想录算法训练营第三十四天 | LeetCode 860. 柠檬水找零、406. 根据身高重建队列、452. 用最少数量的箭引爆气球
    Redis的持久化机制
    怎样不依靠工资收入赚到一万元?
    破局DevOps|8大北极星指标指引研发效能方向
    [免费专栏] Android安全之APK动态方式逆向应用【三种Smali注入方法】
    把zoom视频会议web客户端嵌入企业平台
    基于Java+SpringBoot+vue实现图书借阅和销售商城一体化系统
    C++最后一次实验及实验总结
  • 原文地址:https://www.cnblogs.com/FatTiger4399/p/17794508.html