简单实现vue2的数据响应式原理,加深理解

实现原理

画的一般将就看看
画的一般将就看看

代码

class Vue{
      constructor(options){
        this.options = options;
        this.$data = options.data;
        this.$el = document.querySelector(options.el);

        new Observer(this.$data);//监听data所有的属性
        this._proxy();//代理,可以通过vue.name 访问data.name的值
        new Compiler(this.$el, this);//解析模板
      }
      _proxy(){//代理把data的属性一个个添加到vue中
        Object.keys(this.$data).forEach(key => {
          Object.defineProperty(this, key, {
            configurable:true,
            enumerable:true,
            get(){
              return this.$data[key];
            },
            set(newVal){
              this.$data[key] = newVal;
            }
          })
        })
      }
    }
    /**
	*通过Object.defineProperty重写get、set方法实现监听
	*get获取值时,dep添加Watcher对象
	*set更新数据时,dep.notify通知所有订阅的Watcher对象执行update方法更新数据
	*/
    class Observer{//监听
      constructor(data){
        this.$data = data;
        this.defineReactive();
      }
      defineReactive(){
        Object.keys(this.$data).forEach(key => {
          const dep = new Dep();//为属性创建Dep
          let val = this.$data[key];
          Object.defineProperty(this.$data, key, {
            configurable:true,
            enumerable:true,
            get(){
              if(Dep.target){//解析模板时创建Watcher实例,Dep.target指向这个实例
                dep.addSubs(Dep.target);//添加订阅者
              }
              return val
            },
            set(newVal){
              if(newVal === val){
                return;
              }
              val = newVal;
              dep.notify();//通知所有订阅者update数据
            }
          })
        })
      }
    }
    class Dep{
      constructor(){
        this.subs = [];
      }
      addSubs(sub){//添加订阅者
        this.subs.push(sub);
      }
      notify(){//通知所有订阅者更新数据
        this.subs.forEach(sub=>{
          sub.update();
        })
      }
    }
    const reg = /\{\{(.*)\}\}/
    class Compiler{//解析模板
      constructor(el, vm){
        this.$el = el;
        this.$vm = vm;
        this.frag = this.createDocumentFragment();//创建虚拟节点
        this.$el.appendChild(this.frag);//虚拟节点挂载到页面
      }
      createDocumentFragment(){
        const frag = document.createDocumentFragment();//创建虚拟节点
        let child;
        while(child = this.$el.firstChild){//获取第一个节点
          this._compiler(child);//解析
          //添加节点,appendChild会把this.$el.firstChild,移到创建的虚拟节点。
          //所以可以while(child = this.$el.firstChild)一直遍历
          frag.appendChild(child);
        }
        return frag;
      }
      _compiler(node){//只实现了简单的文本节点
        if(node.nodeType === 3){//文本节点
          if(reg.test(node.nodeValue)){//匹配到{{name}}
            const name = RegExp.$1.trim();
            new Watcher(node, name, this.$vm)//创建Watcher实例
          }
        }
      }
    }
    class Watcher{
      constructor(node, name, vm){
        this.node = node;
        this.name = name;
        this.vm = vm;
        Dep.target = this; //Dep.target指向Watcher本身(get时添加到dep中的数据来自于这)
        this.update();//更新数据把data中的数据更新到模板:类似{{name}}=>张三
        Dep.target = null;//更新数据时get方法把Watcher添加到dep中,此时完成了使命可以为null
      }
      update(){//把data中的数据添加到模板中
        this.node.nodeValue = this.vm[this.name]
      }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值