浅谈vue,angular,react数据双向绑定原理分析


Posted in Javascript onNovember 28, 2017

传统做法

前端维护状态,手动操作DOM更新视图。前端框架对服务器数据通过模版进行渲染。当用户产生了一个动作之后,我们通过document.getElementBy... 手动进行DOM更新。
框架帮忙分离数据和视图,后续状态更新需要手动操作DOM,因为框架只管首次渲染,不追踪状态监听变化。

双向数据绑定

当我们在前端开发中采用MV*的模式时,M - model,指的是模型,也就是数据,V - view,指的是视图,也就是页面展现的部分。通常,我们需要编写代码,将从服务器获取的数据进行“渲染”,展现到视图上。每当数据有变更时,我们会再次进行渲染,从而更新视图,使得视图与数据保持一致。

浅谈vue,angular,react数据双向绑定原理分析

页面也会通过用户的交互,产生状态、数据的变化,这个时候,我们则编写代码,将视图对数据的更新同步到数据,以致于同步到后台服务器。也就是

浅谈vue,angular,react数据双向绑定原理分析

不同的前端 MV* 框架对于这种 Model 和 View 间的数据同步有不同的处理。在 Backbone 中,Model 到 View 的数据传递,可以在 View 中监听 Model 的 change 事件,每当 Model 更新,View 中重新执行 render。而 View 到 Model 的数据传递,可以监听 View 对应的 DOM 元素的各种事件,在检测到 View 状态变更后,将变更的数据发送到 Model(通过两边的监听事件)。相较于 Backbone,AngularJS 所代表的 MVVM 框架则更进一步,从框架层面支持这种数据同步机制,而且是双向数据绑定:

浅谈vue,angular,react数据双向绑定原理分析

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

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

VueJS 则使用 ES5 提供的 Object.defineProperty() 方法,监控对数据的操作,从而可以自动触发数据同步。并且,由于是在不同的数据上触发同步,可以精确的将变更发送给绑定的视图,而不是对所有的数据都执行一次检测。

Vue 双向数据绑定实现

数据与视图的绑定与同步,最终体现在对数据的读写处理过程中,也就是 Object.defineProperty() 定义的数据 set、get 函数中。Vue 中对于的函数为 defineReactive,在精简版实现中,我只保留了一些基本特性:

function defineReactive(obj, key, value){
    var dep = new Dep();
    Object.defineProperty(obj, key, {
      enumerable: true,
      configurable: true,
      get: function reactGetter(){
        if(Dep.target){
          dep.depend();
        }
        return value;
      },
      set: function reactSetter(newVal){
        if (value === newVal) {
          return;
        } else {
          value = newVal;
          //如果数据发生改变,则通知所有的 watcher(借助 dep.notify())
          dep.notify();
        }
      }
    })
  }

在对数据进行读取时,如果当前有 Watcher(对数据的观察者,watcher 会负责将获取的新数据发送给视图),那将该 Watcher 绑定到当前的数据上(dep.depend(),dep 关联当前数据和所有的 watcher 的依赖关系),是一个检查并记录依赖的过程。而在对数据进行赋值时,如果数据发生改变,则通知所有的 watcher(借助 dep.notify())。这样,即便是我们手动改变了数据,框架也能够自动将数据同步到视图。

数据绑定关系的识别过程

Vue 和 AngularJS 中,都是通过在 HTML 中添加指令的方式,将视图元素与数据的绑定关系进行声明

<form id="test">
    <input type="text" v-model="name">
  </form>

以上的 HTML 代码表示该 input 元素与 name 数据进行绑定。在 JS 代码中可以这样进行初始化:

var vm = new Vue({
   el: '#test',
   data: {
    name: 'sysuzhyupeng'
   }
  })

代码正确执行后,页面上 input 元素对应的位置会显示上面代码中给出的初始值:sysuzhyupeng。

执行 vm.name = ‘zhyupeng' 后,页面上 input 也会更新为显示: zhyupeng。在页面文本框中修改内容为:yupeng,则通过vm.name 获取的值为:'yupeng'

React数据绑定

React采用这种方式,考虑虚拟DOM树的更新:

  1. 属性更新,组件自己处理
  2. 结构更新,重新“渲染”子树(虚拟DOM),找出最小改动步骤,打包DOM操作,给真实DOM树打补丁

单纯从数据绑定来看,React虚拟DOM没有数据绑定,因为setState()不维护上一个状态(状态丢弃),谈不上绑定

从数据更新机制来看,React类似于提供数据模型的方式(必须通过state更新)

没有双向数据绑定的话,input的双向场景要怎么实现?通过框架提供的API,手动通知数据变化,和操作DOM的方式很像

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
有趣的JavaScript数组长度问题代码说明
Jan 20 Javascript
Jquery实现带动画效果的经典二级导航菜单
Mar 22 Javascript
IE8中使用javascript动态加载CSS的解决方法
Jun 17 Javascript
一个很有趣3D球状标签云兼容IE8
Aug 22 Javascript
js使用split函数按照多个字符对字符串进行分割的方法
Mar 20 Javascript
JS实现回到页面顶部动画效果的简单实例
May 24 Javascript
JS实现星星评分功能实例代码(两种方法)
Jun 09 Javascript
利用JQuery直接调用asp.net后台的简单方法
Oct 27 Javascript
第一次接触神奇的前端框架vue.js
Dec 01 Javascript
JavaScript严格模式详解
Jan 16 Javascript
vue-router相关基础知识及工作原理
Mar 16 Javascript
前端Electron新手入门教程详解
Jun 21 Javascript
JS+HTML+CSS实现轮播效果
Nov 28 #Javascript
vue中使用vue-router切换页面时滚动条自动滚动到顶部的方法
Nov 28 #Javascript
解决在vue+webpack开发中出现两个或多个菜单公用一个组件问题
Nov 28 #Javascript
vue-music关于Player播放器组件详解
Nov 28 #Javascript
JavaScript数据结构之双向链表和双向循环链表的实现
Nov 28 #Javascript
JS实现的找零张数最小问题示例
Nov 28 #Javascript
JavaScript数据结构之单链表和循环链表
Nov 28 #Javascript
You might like
PHP isset()与empty()的使用区别详解
2010/08/29 PHP
PHP下利用header()函数设置浏览器缓存的代码
2010/09/01 PHP
ajax在joomla中的原生态应用代码
2012/07/19 PHP
js实现图片拖动改变顺序附图
2014/05/13 Javascript
javascript图片滑动效果实现
2021/01/28 Javascript
JavaScript实现多种排序算法
2016/02/24 Javascript
AngularJS在IE下取数据总是缓存问题的解决方法
2016/08/05 Javascript
Angular中的$watch、$watchGroup、$watchCollection
2017/06/25 Javascript
详解如何提高 webpack 构建 Vue 项目的速度
2017/07/03 Javascript
浅析JavaScript中的平稳退化(graceful degradation)
2017/07/24 Javascript
JavaScript for循环 if判断语句(学习笔记)
2017/10/11 Javascript
jquery实现点击a链接,跳转之后,该a链接处显示背景色的方法
2018/01/18 jQuery
从parcel.js打包出错到选择nvm的全部过程
2018/01/23 Javascript
Vue中使用 setTimeout() setInterval()函数的问题
2018/09/13 Javascript
Vue 2.0 中依赖注入 provide/inject组合实战
2019/06/20 Javascript
通过实例解析jQ Ajax操作相关原理
2020/09/23 Javascript
JS removeAttribute()方法实现删除元素的某个属性
2021/01/11 Javascript
Django在Win7下的安装及创建项目hello word简明教程
2014/07/14 Python
Python多线程编程(二):启动线程的两种方法
2015/04/05 Python
在Python的Django框架中编写编译函数
2015/07/20 Python
python中使用正则表达式的连接符示例代码
2017/10/10 Python
将tensorflow的ckpt模型存储为npy的实例
2018/07/09 Python
Django REST Framework之频率限制的使用
2019/09/29 Python
有关HTML5 Video对象的ontimeupdate事件(Chrome上无效)的问题
2013/07/19 HTML / CSS
基于HTML5的WebGL实现json和echarts图表展现在同一个界面
2017/10/26 HTML / CSS
东南亚地区最大的购物网站Lazada新加坡站点:Lazada.sg
2016/07/17 全球购物
美国户外运动商店:Sun & Ski
2018/08/23 全球购物
俄罗斯天然和有机产品、健康生活网上商店:Fitomarket.ru
2020/10/09 全球购物
无锡灵山大佛导游词
2015/02/09 职场文书
复兴之路观后感3000字
2015/06/02 职场文书
活动宣传稿范文
2015/07/23 职场文书
银行柜员工作心得体会
2016/01/23 职场文书
《时代广场的蟋蟀》读后感:真挚友情,温暖世界!
2020/01/08 职场文书
Python机器学习三大件之一numpy
2021/05/10 Python
探究Mysql模糊查询是否区分大小写
2021/06/11 MySQL
MySQL中优化SQL语句的方法(show status、explain分析服务器状态信息)
2022/04/09 MySQL