浅谈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 相关文章推荐
jQuery div层的放大与缩小简单实现代码
Mar 28 Javascript
判断ie的两种简单方法
Aug 12 Javascript
JS实现根据出生年月计算年龄
Jan 10 Javascript
Node.js中使用jQuery的做法
Aug 17 Javascript
javascript实现鼠标点击页面 移动DIV
Dec 02 Javascript
Jquery EasyUI $.Parser
Jun 02 jQuery
前端MVVM框架解析之双向绑定
Jan 24 Javascript
jQuery 实现倒计时天,时,分,秒功能
Jul 31 jQuery
JS模拟浏览器实现全局搜索功能
Sep 11 Javascript
详解vue-router 动态路由下子页面多页共活的解决方案
Dec 22 Javascript
手机浏览器唤起微信分享(JS)
Oct 11 Javascript
解决vue页面刷新,数据丢失的问题
Nov 24 Vue.js
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+highchats生成动态统计图
2014/05/21 PHP
Thinkphp中volist标签mod控制一定记录的换行BUG解决方法
2014/11/04 PHP
PHP curl CURLOPT_RETURNTRANSFER参数的作用使用实例
2015/02/07 PHP
thinkphp3.x中cookie方法的用法分析
2016/05/19 PHP
php 函数使用可变数量的参数方法
2017/05/02 PHP
php生成静态页面并实现预览功能
2019/06/27 PHP
Yii框架安装简明教程
2020/05/15 PHP
jQuery 源码分析笔记(6) jQuery.data
2011/06/08 Javascript
jQuery中:not选择器用法实例
2014/12/30 Javascript
jQuery垂直多级导航菜单代码分享
2015/08/18 Javascript
微信小程序实战之自定义toast(6)
2017/04/18 Javascript
微信小程序开发之toast提示插件使用示例
2017/06/08 Javascript
jQuery轻量级表单模型验证插件
2018/10/15 jQuery
Vue 嵌套路由使用总结(推荐)
2020/01/13 Javascript
Vue使用自定义指令实现拖拽行为实例分析
2020/06/06 Javascript
Python下载网络文本数据到本地内存的四种实现方法示例
2018/02/05 Python
python实现数独游戏 java简单实现数独游戏
2018/03/30 Python
Django学习教程之静态文件的调用详解
2018/05/08 Python
python获取微信小程序手机号并绑定遇到的坑
2018/11/19 Python
Python实现Linux监控的方法
2019/05/16 Python
解决win7操作系统Python3.7.1安装后启动提示缺少.dll文件问题
2019/07/15 Python
python爬虫 正则表达式解析
2019/09/28 Python
Pycharm无法打开双击没反应的问题及解决方案
2020/08/17 Python
python 多线程死锁问题的解决方案
2020/08/25 Python
Volcom英国官方商店:美国殿堂级滑板、冲浪、滑雪服装品牌
2019/03/13 全球购物
数据库的约束含义
2012/09/09 面试题
物流管理专业应届生求职信
2013/11/21 职场文书
学术会议主持词
2014/03/17 职场文书
乔迁之喜主持词
2014/03/27 职场文书
临床医师个人自我评价
2014/04/06 职场文书
小学生学雷锋演讲稿
2014/04/25 职场文书
天地会口号
2014/06/17 职场文书
高三生物教学反思
2016/02/22 职场文书
python基于tkinter制作无损音乐下载工具
2021/03/29 Python
PHP策略模式写法
2021/04/01 PHP
基于Python实现的购物商城管理系统
2021/04/27 Python