• Vue.js MVVM及数据绑定原理


    什么是数据驱动

    数据驱动是vuejs最大的特点。在vuejs中,所谓的数据驱动就是当数据发生变化的时候,用户界面发生相应的变化,开发者不需要手动的去修改dom

    比如说我们点击一个button,需要元素的文本进行是和否的切换。

    在jquery刀耕火种的年代中,对于页面的修改我们一般是这样的一个流程,我们对button绑定事件,然后获取文案对应的元素dom对象,然后根据切换修改该dom对象的文案值。

    而对于vuejs实现这个功能的流程,只需要在button元素上指明事件,同时声明对应文案的属性,点击事件的时候改变属性的值,对应元素的文本就能够自动的进行切换,我们不需要像以前那样手动的操作dom。

    简而言之,就是vue.js帮我们封装了数据和dom对象操作的映射,我们只需要关心数据的逻辑处理,数据的变化就能够自然的通知页面进行页面的重新渲染

    这样做的确实给我们带来的好处,我们不需要再在代码中频繁地去操作dom了,在实际项目中,我们有很大部分代码都是在数据修改以后,手动操作重新渲染页面元素,当页面越来越复杂的时候,页面代码组织会越来难以维护。同时,js对dom的频繁操作,会使得页面代码的出错概率高,页面的视图展示会融合在js代码中,对于页面视图显示的升级也不友好。

    那么vuejs是如何实现这种数据驱动的呢?

    MVVM框架

    Vuejs的数据驱动是通过MVVM这种框架来实现的。MVVM框架主要包含3个部分:model、view和 viewmodel。

    Model:指的是数据部分,对应到前端就是javascript对象

    View:指的是视图部分,对应前端就是dom

    Viewmodel:就是连接视图与数据的中间件

    数据(Model)和视图(View)是不能直接通讯的,而是需要通过ViewModel来实现双方的通讯。当数据变化的时候,viewModel能够监听到这种变化,并及时的通知view做出修改。同样的,当页面有事件触发时,viewMOdel也能够监听到事件,并通知model进行响应。Viewmodel就相当于一个观察者,监控着双方的动作,并及时通知对方进行相应的操作。

    Vuejs的数据驱动实现

    不同的 MVVM 框架中,实现双向数据绑定的技术有所不同

    AngularJS 采用“脏值检测”的方式,数据发生变更后,对于所有的数据和视图的绑定关系进行一次检测,识别是否有数据发生了改变,有变化进行处理,可能进一步引发其他数据的改变,所以这个过程可能会循环几次,一直到不再有数据变化发生后,将变更的数据发送到视图,更新页面展现。如果是手动对 ViewModel 的数据进行变更,为确保变更同步到视图,需要手动触发一次“脏值检测”。
    
    

    vue.js在实例化的过程中,会对遍历传给实例化对象选项中的data 选项,遍历其所有属性并使用 Object.defineProperty 把这些属性全部转为 getter/setter

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

    访问器属性的"值"比较特殊,读取或设置访问器属性的值,实际上是调用其内部特性:get和set函数。

     get 和 set 方法内部的 this 都指向 obj,这意味着 get 和 set 函数可以操作对象内部的值。

    另外,访问器属性的会"覆盖"同名的普通属性。

    同时每一个实例对象都有一个watcher实例对象,他会在模板编译的过程中,用getter去访问data的属性,watcher此时就会把用到的data属性记为依赖,这样就建立了视图与数据之间的联系。当之后我们渲染视图的数据依赖发生改变(即数据的setter被调用)的时候,watcher会对比前后两个的数值是否发生变化,然后确定是否通知视图进行重新渲染。

    这样就实现了所谓的数据对于视图的驱动。

    当 new 一个 Vue,主要做了两件事:

    第一个是监听数据:observe(data),

    第二个是编译 HTML:nodeToFragement(id)。

    使用文档片段处理节点,速度和性能远远优于直接操作 DOM。

    Vue 进行编译时,就是将挂载目标的所有子节点劫持(真的是劫持,通过 append 方法,DOM 中的节点会被自动删除)到 DocumentFragment 中,经过一番处理后,再将 DocumentFragment 整体返回插入挂载目标。

    在监听数据的过程中,会为 data 中的每一个属性生成一个主题对象 dep。

    在编译 HTML 的过程中,会为每个与数据绑定相关的节点生成一个订阅者 watcher,watcher 会将自己添加到相应属性的 dep 中。

    发出通知 dep.notify() => 触发订阅者的 update 方法 => 更新视图

     在编译 HTML 过程中,为每个与 data 关联的节点生成一个 Watcher。Watcher 函数中发生了什么呢

          首先,将自己赋给了一个全局变量 Dep.target;

           其次,执行了 update 方法,进而执行了 get 方法,get 的方法读取了 vm 的访问器属性,从而触发了访问器属性的 get 方法,get 方法中将该 watcher 添加到了对应访问器属性的 dep 中;

           再次,获取属性的值,然后更新视图。

           最后,将 Dep.target 设为空。因为它是全局变量,也是 watcher 与 dep 关联的唯一桥梁,任何时刻都必须保证 Dep.target 只有一个值。

  • 相关阅读:
    VSCode远程编写Shell并实时调试配置过程
    eclispe 无法启动调试 cannot connect to VM
    工作流之设置表访问权限
    利用工作流返回达到无限次重复办理业务的过程
    eworkflow工作流系统在iis中发布
    ie8用ajax访问不能每次都刷新的问题
    视频演示(动态指定执行人+指定申请人的上级)
    视频演示eworkflow集成定制aspx页面的过程
    利用开发框架中的标签库集成报表工具
    流程设计器之标签工具
  • 原文地址:https://www.cnblogs.com/coderL/p/7497603.html
一二三 - 开发者的网上家园