双向数据绑定原理

几种实现双向绑定的做法:

    目前几种主流的mvc(vm)框架都实现了单项数据绑定,而我所理解的双向数据绑定,无非就是在单项数据绑定的基础上给输入元素input textare等添加了change(input)事件,来动态修改model和view,并没有多高深。所以无须介怀是实现的单项或者双向绑定,实现数据绑定 大致几种:

  1. 发布者-订阅者(backbone.js);
    1. 一般通过sub,pub的方式实现数据和视图的绑定监听,更新数据的方式通常是  vm.set('property',vlue);

 

  1. 脏值检查(angular.js);
    1. Angular.js是通过脏值检测的方式比对数据是否有变更。来决定是否更新视图,最简单方式是通过setinterval()定时轮询检测数据变动,当然angular只是在指定的事件触发时进入脏值检测:
      1.   
      2. Ng-click
      3.   
      4. $http
      5.   
      6. $location
      7.   
      8. $timeout $interval
      9.   
      10. $digest()||$apply()
  2. 数据劫持(vue.sj);

Vue.js则采用数据劫持+发布者订阅者模式的方式,通过0bject.defineProperty()来劫持各个属性的setter  getter,在数据发生改变时发布消息给订阅者,触发相应的监听回调。具体整理:

vue是通过数据劫持的方式来做数据绑定,其中核心方法是通过object,defineProperty()来实现对属性的劫持,达到监听数据变动的目的,无疑这个方法是本文中最重要,最基础的内容之一。

Object.defineProperty()直接在一个对象上定义一个新的属性,或者修改一个对象的现有属性,并返回这个对象。

实现mvvm双向数据绑定,步骤:

  1. 实现一个数据监听observer(观察者),能够对数对象的所有属性进行监听,如果有变动可拿到最新值并通知订阅者;
    1. 利用object.defineProperty()来监听属性变动;那么将需要observer的数据对象进行遍历,包括子属性对象的属性,都加上setter和getter这样的话给这个对象的某个值赋值,就会触发setter,从个人监听到数据变化。
    2. 监听到后,怎末通知订阅者呢?所以需要实现一个消息订阅器:维护一个数组,用来手机订阅者,数据变动会触发notify,再调用订阅者的update方法。watcher
  2. 实现一个指令解析器Compile,对每个元素的指令进行进行扫描和解析,根据指令模板替换数据,以及绑定相应数据;
    1. complile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定跟新函数,方便随时更新视图。
    2. 因为遍历解析的过程有多次dom节点,为了提高性能和效率,会先将节点el转换为文档碎片进行解析编译(js对象虚拟DOM),解析完成后再添加回原来的真实dom节点中。
  3. 实现watcher,作为连接observer和compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定相应的会回调函数,从而跟新试图。
    1. 在自身实例化时往属性订阅器dep里面添加自己;
    2. 自身必须有一个update()方法;
    3. 代属性变动dep.notice()通知时,能调用自身的update()方法,并触发complie中绑定的回调.
  4. mvvm入口函数,整合以上三者;达到数据变化-》视图更新;视图交互变化(input)->数据model变更的双向数据绑定效果;

 

 

 

 

 

 

 

 

MVVM:model   view   view model

数据双向绑定,简化了页面和业务的依赖,解决了数据频繁更新。MvvM在使用当中,利用双向数据绑定计数,使得Model变化时,viewModel  会自动更新,而viewModel 变化时,view也会自动变化。

 

双向数据绑定原理:

采用数据劫持:发布者和订阅者模式的方式,通过object.defineProperty()来劫持各个属性的setter和getter,在数据变动时发布消息给订阅者,出发相应的监听回调;具体步骤:

  1. 当把一个普通的js对象传给VUE实例来作为他的data选项时,vue将遍历他的属性,用object.defineProperty都加上setter和getter方法,这样给这个对象的某个值赋值,就会出发setter,那么就能监听到数据变化;
  2. compile解析模板指令
  3. Watcher 订阅者是observer和compile之间的桥梁,主要做的事:
    1. 在自身实例化时往属性订阅器(dep)里添加自己;
    2. 子集必须有一个update()方法
    3. 待属性变动dep.notice通知时,调取update()方法,并触发compile绑定的回调,则功成身退。
    4. MvvM作为数据的绑定入口,整合observer compile watcher三者:
      1.   
      2. 通过observer来监听自己的model数据变化;
      3.   
      4. 通过compile来解析编译模板指令
      5.   
      6. 最终利用wacher搭起observer和compile之间的通信桥梁,
      7.   
      8. 达到数据变化=>视图跟新;视图交互变化(input)=>数据model变更的双向数据效果。

 

proxy相比defineProperty优势:

Object.defineProperty()三个主要问题:

  1. 不能监听数组变化;
  2. 必须遍历对象的每个属性;
  3. 必须生层次遍历嵌套的对象;

而  ES5的proxy新加入,特点:

  1. 针对对象:针对整个对象而不是对象的某个属性,所以也就不需要keys进行遍历
  2. 支持数组:proxy不需要对数组进行重载,省去了众多hack,减少代码等于减少维护成本。

 

vue中的虚拟DOM:

          虚拟DOM本质就是一个和真实DOM结构类似的Js对象;

        虚拟DOM可以提高浏览器的渲染速度。对比操作Js对象,比操作真实的DOM消耗的性能少的多,特别时                             频繁的操作DOM时,优势彰显的更加明显。

 虚拟DOM步骤:

  1.  在页面首次渲染时,将要渲染的数据全部加载到虚拟DOM中,而后在一次性渲染到真实的DOM上;
  2. 数据变动时,额外生成一个虚拟DOM树,
  3. 通过Diff算法对比修改的部分,而后将修改部分渲染到真实的DOM中;
  4. 释放内存。

你可能感兴趣的