Vue双向数据绑定的理解

本文介绍了MVVM框架的核心概念,重点解析了Vue双向数据绑定的原理。通过Object.defineProperty和观察者设计模式,实现了数据驱动页面和页面改动响应数据的变化。Vue框架的响应式主要涉及数据劫持、编译器、观察者和消息订阅器Dep,详细阐述了这四个关键部分的工作流程。

一、什么是MVVM框架

   所谓MVVM,是Model - View - ViewModel 的简写。

   我的理解是

页面上所看到的就是View。
使用Vue.js或者是其他MVVM框架,是在操作ViewModel,实现View - ViewModel的双向互动。
然后Model就是服务器的资源,ViewMdoel从服务器请求数据,或者发送数据给服务器,就是ViewModel - Model的双向互动。

二、双向数据绑定的原理

    双向数据绑定,双向指的是两个方向。

    一是数据驱动页面,

    二是页面改动了,会响应式的改变绑定的数据。主要是input的变动。

    绑定说的是MVVM框架,自动的去完成数据的改动,页面的渲染。

    不像以前,改变页面上的一个值,要先去获取该元素的节点,然后再去设置它的文本内容(比如innerHTML属性)。

    那么更具体的讲,具体实现主要使用的是,或者说细节是:

    1.Object.defineProperty属性。这是MVVM框架的核心API。

    2.观察者设计模式

    利用Object.defineProperty这个API实现了对Data每个属性的监听和回调。

    数据驱动页面方向:就是当去修改Data某一个属性时,会通知观察者,然后观察者触发自身的回调函数,进而重新渲染页面。

    页面 =》 数据:其实就是去监听input的oninput事件。oninput事件会去修改对应的Data的属性值。


三、浅谈Vue框架实现响应式的原理。

    前面说过,双向数据绑定的核心是Object.definePrototype这个API,Vue的响应式主要做了四方面的工作。

    1.通过Object.definePrototype,劫持了Vue实例对象中的data属性下的每一个值,并设置了相应的getter和setter。

   2.实现了一个compile解析器,将Vue实例对象的el属性挂载的DOM节点下的所有节点进行解析。类似于全部销毁,然后创建一个文档碎片fragment,将识别到的特殊的节点做特殊处理,在放入文档碎片fragment中,最后再讲文档碎片fragment放进根节点,也就是挂载的元素中。

   3.实现了一个观察者watcher,自身有一个updata方法,当数据修改的时候,就会通知观察者调用updata方法,去将相应节点的textContent更新。

   4.实现了一个消息订阅器Dep,用来接收观察者的订阅,并在数据修改时通知观察者。

那么以上观察者如何在Dep中订阅消息,怎么实现这是一个难点。

   简单的说,我的理解。

  参考了一篇文章,

  比如当compile解析器解析到{{message}}这样子的文本节点的时候,就可以认为这个地方绑定了一个变量,就可以实例化一个观察者。看到观察者的代码,

 /*
  	变量的含义:
  	vm:Vue实例对象
  	node:变量所在的文本节点(就是{{message}})
  	name:绑定的变量名(就是message)
    */
    function Watcher(vm,node,name){
        //让全局变量Dep的target属性的指针指向该watcher实例
        Dep.target = this;
        this.vm = vm;
        this.node = node;
        this.name = name;
        //放入Dep.target才能update()?????????????????????????????????????????
        this.update();
        Dep.target = null;
    }
    // 观察者使用update方法,实际上是
    Watcher.prototype = {
        update: function(){
            this.get();
            this.node.nodeValue = this.value;
        },
        //获取data中的属性值 
        get: function(){
            this.value = this.vm[this.name]; //触发相应属性的get
        }
    }
然后在getter中这样定义
 get: function(){
      //Dep.target指针指向watcher,增加订阅者watcher到主体对象Dep
      if(Dep.target){
         dep.addSub(Dep.target);
      }
      return val;
因为在实例化watcher的时候,会执行watcher的updata方法,updata方法中又执行了watcher的get方法,get方法会访问到message属性,触发对应的getter,就会往订阅器Dep中添加watcher。


  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值