美文网首页
vue双向数据绑定原理

vue双向数据绑定原理

作者: lvyweb | 来源:发表于2021-09-22 10:27 被阅读0次

    前置技术点

    1、数组reduce()方法
    应用场景:下次操作的初始值,依赖于上次操作的返回值

    • 数值的累加计算
     //一个数组的所有项累加
        const arr = [2,3,4,6,2,12,34,56]; 
        //    一般实现方案 
        let total = 0;
        arr.forEach((item) => {
            total += item;
        })
        console.log('total--',total);
    
        // 数组的reduce方法,会循环当前的数组,侧重于进行“滚雪球”操作
        // 数组.reduce(函数,初始值)
        // 数组.reduce ((上次计算的结果,当前循环的Item项) => {},0)
        // const 累加的结果 = 数组.reduce((上次计算的结果,当前循环的Item项) => {return 上次的结果+ 当前循环的Item项},0)
        const total2 = arr.reduce((val,item)=>{
            return val+ item;
        })
        console.log('total2--',total2);
    
    • 链式获取对象属性的值

    2、发布订阅模式

    1. Dep类
    • 负责进行依赖收集
    • 首先,有个数组,专门用来存放所有的订阅信息
    • 其次,还要提供一个向数组中追加订阅信息的方法
    • 最后,还要提供一个循环,循环触发数组中的每个订阅信息
      注:只要我们为Vue中data数据重新赋值了,这个赋值的动作,会被Vue监听到,
      然后vue要把数据的变化通知每个订阅者,
      接下来,订阅者(DOM元素)要根据最新的数据,更新自己的内容
    1. Watcher 类
    • 负责订阅一些事件

    3、 使用object.defineProperty()进行数据劫持
    1. 通过get()劫持取值操作
    2. 通过set()劫持赋值操作

        //定义一个数据劫持的方法
        function Observe(obj){
            //这是递归的终止条件
            if(!obj || typeof obj!='object') return;
            //通过Object.keys(obj)获取当前obj上的每个属性
            Object.keys(obj).forEach((key) => {
                //当前被循环的key所对应的属性值
                let value = obj[key];
                //当前被循环的key所对应的属性值
                Observe(value);
                //需要为当前的key所对应的属性,添加getter和setter
                Object.defineProperty(obj,key,{
                    enumerable: true,
                    configurable: true,
                    get(){
                        // console.log(`有人获取了${key}的值`);
                        return value;
                    },
                    set(newVal){
                        value = newVal;
                        Observe(value);
                    }
                })
            })
        }
    

    为什么methods对象下的法可以通过this获得data下的属性

      //属性代理
       object.key((this.$data).forEach((key) => {
           object.defineProperty(this,key,{
               enumerable: true,
               configurable: true,
               get(){
                   return this.$data[key];
               },
               set(newValue){
                   this.$data[key] = newValue;
               }
           })
       }))
    

    对html结构进行模板编译

    //对html结构进行模板编译的方法
    function Compile(el,vm){
        //获取el对应的DOM元素
        vm.$el = document.querySelector(el);
        
        //创建文档碎片,提高DOM操作的性能
        const fragment = document.createDocumentFragment();
        while ((childNode = vm.$el.firstChild)){
            fragment.appendChild(childNode)
        }
    
        //进行模板编译
        vm.$el.appendChild(fragment);
    
     
    }
       //负责对DOM模板进行编译的方法
        function replace(){
            //定义匹配插值表达式的正则
            const regMustache = /\{\{\s*(S+)\s*\}\}/
    
            //证明当前的node节点是一个文本子节点,需要进行正则的替换
            if(node.nodeType === 3){
                //注意:文本子节点,也是一个DOM对象,如果要获取文本子节点的字符串内容,需要调用textContent属性获取
                const text = node.textContent;
                const execResult = regMustache.exec(text);
    
                console.log(execResult)
                if(execResult){
                    const value = execResult[1].split('.').reduce((newObj,k)=>newObj[k],vm);
                    node.textContent = text.replace(regMustache,value)
                }
                //终止递归的条件
                return 
            }
    
            //证明不是文本节点,可能是一个DOM元素,需要进行递归处理
            node.childNodes.forEach((child) => replace(child));
        }
    

    最简单的发布订阅

    // 最简单的发布订阅模式
    
    
    // 收集依赖/收集订阅者
    class Dep {
      constructor(){
        //这个subs数组,用来存放所有订阅者的信息
        this.subs = [];
      }
      //向subs数组中,添加订阅者信息
      addSub(watcher){
        this.subs.push(watcher);
      }
    
    
    // 发布通知的方法
    notify(){
      this.subs.forEach((watcher) => watcher.update());
    }
    
    }
    
    //订阅者的类
    
    class Watcher{
    
      // cb回调函数中,记录着当前Watcher如何更新自己的文本内容
    // 但是,只知道如何更新自己还不行,还必须拿到最新的数据
    // 因此 还需要在new Watcher 期间,把vm 也传递过来(因为vm中保存着最新的数据)
    // 除此之外,还需知道,在vm身上众多数据中,哪个数据,才是当前自己需要的数据
    // 因此, 必须在new Watcher期间,指定watcher对应的数据名字
    
      constructor(vm,key,cb){
        this.vm = vm;
        this.key = key;
        this.cb = cb;
      }
      // watcher 的实例,需要有update函数,从而让发布者能够通知我们进行更新
      update(){
        this.cb()
      }
    }
    
    const w1 = new Watcher(() =>{
      console.log('我是第一个订阅者')
    })
    

    相关文章

      网友评论

          本文标题:vue双向数据绑定原理

          本文链接:https://www.haomeiwen.com/subject/fruwgltx.html