浅析vue中双向数据绑定

 一:双向数据绑定

简介:  

vue是一个mvvm框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟        着同步变化。

原理:

var obj = {
      foo: 'foo'
    }

    Object.defineProperty(obj, 'foo', {
      get: function () {
        console.log('将要读取obj.foo属性');
      }, 
      set: function (newVal) {
        console.log('当前值为', newVal);
      }
    });

    obj.foo; // 将要读取obj.foo属性
    obj.foo = 'name'; // 当前值为 name


//  get为我们访问属性时调用,set为我们设置属性值时调用。
  • vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

  • 第一步:需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter。这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化;

  • 第二步:compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图;

  • 第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:

    • 1、在自身实例化时往属性订阅器(dep)里面添加自己

    • 2、自身必须有一个update()方法

    • 3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。

  • 第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。

                         浅析vue中双向数据绑定_第1张图片

二:diff流程

1:当数据发生变化时,vue是怎么更新节点的?

   我们先根据真实DOM生成一颗virtual DOM,当virtual DOM某个节点的数据改变后会生成一个新的Vnode,然后VnodeoldVnode作对比,发现有不一样的地方就直接修改在真实的DOM上,然后使oldVnode的值为Vnode

diff的过程就是调用名为patch的函数,比较新旧节点,一边比较一边给真实的DOM打补丁,更新相应的视图。

                                   浅析vue中双向数据绑定_第2张图片

2. virtual DOM和真实DOM的区别?

virtual DOM是将真实的DOM的数据抽取出来,以对象的形式模拟树形结构。比如dom是这样的:

123

对应的virtual DOM(伪代码):

var Vnode = {
    tag: 'div',
    children: [
        { tag: 'p', text: '123' }
    ]
};

VNodeoldVNode都是对象

3:diff流程

  • patch函数接收两个参数oldVnode和Vnode分别代表新的节点和之前的旧节点
    • 判断两节点是否值得比较,值得比较则执行patchVnode;
    • 不值得比较则用Vnode替换oldVnode;
  • patchVnode:当我们确定两个节点值得比较之后我们会对两个节点指定patchVnode方法;
    • 找到对应的真实dom,称为el;
    • 判断Vnode和oldVnode是否指向同一个对象,如果是,那么直接return;
    • 如果他们都有文本节点并且不相等,那么将el的文本节点设置为Vnode的文本节点;
    • 如果oldVnode有子节点而Vnode没有,则删除el的子节点;
    • 如果oldVnode没有子节点而Vnode有,则将Vnode的子节点真实化之后添加到el;
    • 如果两者都有子节点,则执行updateChildren函数比较子节点,这一步很重要;
  • updateChildren函数图解

浅析vue中双向数据绑定_第3张图片

现在分别对oldS、oldE、S、E两两做sameVnode比较,有四种比较方式,当其中两个能匹配上那么真实dom中的相应节点会移到Vnode相应的位置,这句话有点绕,打个比方:

  • 如果是oldS和E匹配上了,那么真实dom中的第一个节点会移到最后;
  • 如果是oldE和S匹配上了,那么真实dom中的最后一个节点会移到最前,匹配上的两个指针向中间移动;
  • 如果四种匹配没有一对是成功的,那么遍历oldChild,S挨个和他们匹配,匹配成功就在真实dom中将成功的节点移到最前面,如果依旧没有成功的,那么将S对应的节点插入到dom中对应的oldS位置,oldS和S指针向中间移动。

 

 

 

 

 

你可能感兴趣的:(vue.js,vue)