浅谈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获取textarea中的光标位置
May 06 Javascript
js 禁止选择功能实现代码(兼容IE/Firefox)
Apr 23 Javascript
文本框文本自动补全效果示例分享
Jan 19 Javascript
ECMAScript6中Map/WeakMap详解
Jun 12 Javascript
JS实现图文并茂的tab选项卡效果示例【附demo源码下载】
Sep 21 Javascript
概述VUE2.0不可忽视的很多变化
Sep 25 Javascript
详解js前端代码异常监控
Jan 11 Javascript
ECMAScript6变量的解构赋值实例详解
Sep 19 Javascript
vue组件中watch props根据v-if动态判断并挂载DOM的问题
May 12 Javascript
Vue 中 a标签上href无法跳转的解决方式
Nov 12 Javascript
JS实现炫酷雪花飘落效果
Aug 19 Javascript
vue mvvm数据响应实现
Nov 11 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 mssql 数据库分页SQL语句
2008/12/16 PHP
PHP实现利用MySQL保存session的方法
2014/08/23 PHP
php相对当前文件include其它文件的方法
2015/03/13 PHP
总结的一些PHP开发中的tips(必看篇)
2017/03/24 PHP
PHP 传输会话curl函数的实例详解
2017/09/12 PHP
PHP开发实现快递查询功能详解
2019/04/08 PHP
关于Yii2框架跑脚本时内存泄漏问题的分析与解决
2019/12/01 PHP
jQuery 使用个人心得
2009/02/26 Javascript
ExtJs使用总结(非常详细)
2012/03/22 Javascript
JavaScript中的this关键字介绍与使用实例
2013/06/21 Javascript
js+html5获取用户地理位置信息并在Google地图上显示的方法
2015/06/05 Javascript
JavaScript实现简单获取当前网页网址的方法
2015/11/09 Javascript
JavaScript中eval()函数用法详解
2015/12/14 Javascript
有关jquery与DOM节点操作方法和属性记录
2016/04/15 Javascript
基于JS实现Android,iOS一个手势动画效果
2016/04/27 Javascript
jquery实现垂直和水平菜单导航栏
2020/08/27 Javascript
AngularJS bootstrap启动详解及实例代码
2016/09/14 Javascript
微信小程序实现人脸识别
2018/05/25 Javascript
教你如何编写Vue.js的单元测试的方法
2018/10/17 Javascript
ES6中Symbol、Set和Map用法详解
2019/08/20 Javascript
vue实现将数据存入vuex中以及从vuex中取出数据
2019/11/08 Javascript
[00:23]DOTA2群星共贺开放测试 25日无码时代来袭
2013/09/23 DOTA
Python实现的生成自我描述脚本分享(很有意思的程序)
2014/07/18 Python
十个Python程序员易犯的错误
2015/12/15 Python
python使用opencv读取图片的实例
2017/08/17 Python
Python数据结构之顺序表的实现代码示例
2017/11/15 Python
Python程序打包工具py2exe和PyInstaller详解
2019/06/28 Python
英国领先的露营和露营车品牌之一:OLPRO
2019/08/06 全球购物
群众路线教育党课主持词
2014/04/01 职场文书
音乐教师求职信
2014/06/28 职场文书
债务授权委托书范本
2014/10/17 职场文书
亚布力滑雪场导游词
2015/02/09 职场文书
党员转正党支部意见
2015/06/02 职场文书
2016年毕业实习心得体会范文
2015/10/09 职场文书
《槐乡的孩子》教学反思
2016/02/20 职场文书
Android开发实现极为简单的QQ登录页面
2022/04/24 Java/Android