Vue响应式原理(个人理解)

  • Wather类: 观察数据变化并执行回调
  • Compile类: 相当于解析DOM,处理插值表达式替换数据
  • Dep类: 收集依赖,通知更新
  • Observe类: 响应式数据,遍历对象key。并实现一个defineReactive方法定义响应式数据

发布订阅模式

在这里插入图片描述

class Watcher{
    constructor(vm,key,callback){
        this.vm = vm;
        this.key = key;
        this.callback = callback;
        Dep.target = this;

        this.oldValue = vm[key];
        Dep.target = null;
    }
    update(){
        const newValue = this.vm[this.key];
        if(newValue === this.oldValue) return
        this.callback(newValue);
        this.oldValue = newValue;
    }
}  

class Compile{  //处理结构里的
    constructor(vm){
        this.vm = vm ;
        this.el = vm.$el;
        this.compile(this.el); 

    }
    compile(el){  //有子节点
        const childNodes = el.childNodes; //把所有节点类型弄进来
        Array.from(childNodes).forEach(node=>{
            //遍历判断
            if(node.nodeType === 3){ //文本节点
                this.compileText(node);
            }else if(node.nodeType === 1){ //元素节点

            }


            if(node.childNodes && node.childNodes.length){  //如果这个节点还有子节点就再compile
                this.compile(node);
            }

        })
    }
    compileText(node){ //处理文本类型节点
        const reg = /\{\{(.+?)\}\}/g  //匹配插值表达式
        const value = node.textContent.replace(/\s/g,''); 
        const tokens = [];  //保存要拆分的多个部分

        let result,index,lastIndex = 0;
        while(result = reg.exec(value)){
            index = result.index;
            if(index > lastIndex){
                tokens.push(value.slice(lastIndex,index));
            }
            const key = result[1].trim();
            tokens.push(this.vm[key]);   //放入对应想要的值,比如{{mytite}},放进vm[mytitle]
            lastIndex = index + result[0].length;


            const pos = tokens.length - 1;
            //更新操作
            new Watcher(this.vm,key,newValue=>{
                tokens[pos] = newValue;
                node.textContent = tokens.join('');
            })
          
        }
        if(lastIndex < value.length){
            tokens.push(value.slice(lastIndex));
        }
        if(tokens.length){
            node.textContent = tokens.join('');
        }
    }
}

class Dep{
    constructor(){
        this.subs = [];
    }
    addSub(sub){
        this.subs.push(sub);
    }
    notify(){
        this.subs.forEach(sub=> sub.update());
    }
}


class Observer{  //响应式数据data是对象?
    constructor(data){
        this.data = data;
        this.dep = new Dep()
        this.walk(data);  //遍历对象属性? 
    }
    walk(data){
        const dep = this.dep; 
        Object.keys(data).forEach(key=> defineReactive(data,key,data[key],dep)); 

    }
}
function defineReactive(data,key,value,dep){
    if(typeof value === 'obejct' && value!==null){
        return new Observer(value);
    }
    Object.defineProperty(data,key,{
        enumerable:true,
        configurable:true,
        get(){
            Dep.target && dep.addSub(Dep.target);  //增加视图?
            return value; 
        },
        set(newValue){
            if(value  === newValue) return //如果值还是原来那个没必要更新
            value = newValue;
            if(typeof value === 'object' && value!==null){
                return new Observer(value);
            }
            dep.notify(); //通知更新
        }
    })
}



class Vue{
    constructor(options){
        this.$options = options || {};
        this.$data = options.data || {};  
        const el = options.el;
        this.$el = typeof el === 'string' ? document.querySelector(el): del;
 
        //1.将属性注入到Vue实例
        proxy(this,this.$data);  //就相当于把data里面的属性交给Vue代理,就相当于添加到了Vue实例的属性
        //2.创建Observer进行 data 属性变化的观察
        new Observer(this.$data);     
        //3.视图解析
        new Compile(this); 
    } 
}
function proxy(target,data){
    Object.keys(data).forEach(key=>{
        Object.defineProperty(target,key,{
            enumerable:true,
            configurable:true,
            get(){
                return data[key];
            },
            set(newValue){
                data[key] = newValue;
            }
        })
    })
}

实现:

   <div id="app"> 
        {{mytitle}} {{mytitle}}
        <h2>{{nihao}}</h2> 
    </div> 
    <script src="./vue.js"></script>
    <script>
        let vue = new Vue({
            el:'#app', 
            data:{
                mytitle:"shabi",
                nihao:"我是你好", 
            }     
        });
        console.log(vue); 



     </script> 

整个流程图解(个人理解)

在这里插入图片描述

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值