vue双向绑定的原理
什么是双向数据绑定?Vue是一个MVVM框架,数据绑定简单来说,就是当数据发生变化时,相应的视图会进行更新,当视图更新时,数据也会跟着变化。
实现数据绑定的方式大致有以下几种:
- 1、发布者-订阅者模式(backbone.js)
- 2、脏值检查(angular.js)
- 3、数据劫持(vue.js)
发布者-订阅者模式
一般通过sub, pub的方式实现数据和视图的绑定监听,更新数据方式通常做法是 vm.set('property', value),有兴趣可参考这里
我们更希望可以通过 vm.property = value 这种方式进行数据更新,同时自动更新视图。
脏值检查
angular是通过脏值检查方式来对比数据是否变化,来决定是否更新视图,最常见的方式是通过setInterval()来监测数据变化,当然,只会在某些指定事件触发时下才进行脏值检查。大致如下:
- DOM事件,譬如用户输入文本,点击按钮等。( ng-click )
- XHR响应事件 ( $http )
- 浏览器Location变更事件 ( $location )
- Timer事件( $timeout , $interval )
- 执行 $digest() 或 $apply()
数据劫持
Vue.js则是通过数据劫持以及结合发布者-订阅者来实现的,数据劫持是利用ES5的Object.defineProperty(obj, key, val)来劫持各个属性的的setter以及getter,在数据变动时发布消息给订阅者,从而触发相应的回调来更新视图。
一、实现最基础的数据绑定
<input type="text" id="in"/>
输入的值为:<span id="out"></span> <script>
var int = document.getElementById('in');
var out = document.getElementById('out');
var obj = {}; Object.defineProperty(obj, 'msg', {
enumerable: true,
configurable: true,
set (newVal) {
out.innerHTML = newVal;
}
}) int.addEventListener('input', function(e) {
obj.msg = e.target.value;
})
</script>
Object.defineProperty()的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性:里面有三个值,分别如下:
- obj 需要定义属性的当前对象
- prop 当前需要定义的属性名
- desc 属性描述符
- 一般通过为对象的属性赋值的情况下,对象的属性可以修改也可以删除,但是通过Object.defineProperty()定义属性,通过描述符的设置可以进行更精准的控制对象属性。
有兴趣可以深入了解,这里就不多解释了=。=
二、双向数据绑定实现(此处用MVue替代)
上面的只是简单的使用了Object.defineProperty(),并不是我们最终想要的效果,最终想要的效果如下:
<div id="app">
<input type="text" v-model="text">
输入的值为:{{text}}
<div>
<input type="text" v-model="text">
</div>
</div>
<script>
var vm = new MVue({
el: '#app',
data: {
text: 'hello world'
}
})
</script>
实现思路:
1、输入框以及文本节点和data中的数据进行绑定
2、输入框内容变化时,data中的对应数据同步变化,即 view => model
3、data中数据变化时,对应的文本节点内容同步变化 即 model => view
上述流程如图所示:
1、实现一个数据监听器Obverser,对data中的数据进行监听,若有变化,通知相应的订阅者。
2、实现一个指令解析器Compile,对于每个元素上的指令进行解析,根据指令替换数据,更新视图。
3、实现一个Watcher,用来连接Obverser和Compile, 并为每个属性绑定相应的订阅者,当数据发生变化时,执行相应的回调函数,从而更新视图。
4、构造函数 (new MVue({}))
MVue构造函数
在初始化MVue实例时,对data中每个属性劫持监听,同时进行模板编译,指令解析,最后挂载到相应的DOM中。
function MVue (options) {
this.$el = options.el;
this.$data = options.data; // 初始化操作,后面会说
// ...
}
1、实现 view => model
DocumentFragment(文档片段)
vue进行编译时,将挂载目标的所有子节点劫持到DocumentFragment中,经过一份解析等处理后,再将DocumentFragment整体挂载到目标节点上。
function nodeToFragment (node, vm) {
var flag = document.createDocumentFragment();
var child;
while (child = node.firstChild) {
compile(child, vm);
if (child.firstChild) {
var dom = nodeToFragment(child, vm);
child.appendChild(dom);
}
flag.appendChild(child);
}
return flag;
}
模板编译(指令解析,事件绑定、初始化数据绑定)
编译过程图
代码如下:
function compile (node, vm) {
let reg = /\{\{(.*)\}\}/;
// 元素节点
if (node.nodeType === 1) {
var attrs = node.attributes;
for (let attr of attrs) {
if (attr.nodeName === 'v-model') {
// 获取v-model指令绑定的data属性
var name = attr.nodeValue;
// 绑定事件
node.addEventListener('input', function(e) {
vm.$data[name] = e.target.value;
})
// 初始化数据绑定
node.value = vm.$data[name];
// 移除v-model 属性
node.removeAttribute('v-model')
}
}
} // 文本节点
if (node.nodeType === 3) {
if (reg.test(node.nodeValue)) {
var name = RegExp.$1 && (RegExp.$1.trim());
// 绑定数据到文本节点中
node.nodeValue = node.nodeValue.replace(new RegExp('\\{\\{\\s*(' + name + ')\\s*\\}\\}'), vm.$data[name]);
}
}
}
现在,我们修改下MVue构造函数,增加模板编译,如下:
function MVue (options) {
this.$el = options.el;
this.$data = options.data; // 模板编译
let elem = document.querySelector(this.$el);
elem.appendChild(nodeToFragment(elem, this))
}
那么,我们的view => model 已经实现了,包括初始化绑定默认值,只要修改了input中的值,data中对应的值相应变化,并触发了setter, 更新属性值等(可以自行在set方法中打印看效果,或者在控制台手动输入vm.$data.text也会看到效果)。
2、实现 model => view
上面可以看出,虽然我们实现了初始化数据绑定,以及输入框变化时,data中text也会变化,但是文本节点仍然没有任何变化,那么如果做到文本节点也同步变化呢,这里用的是发布者-订阅者模式。
vue双向绑定的原理的更多相关文章
- vue双向绑定的原理及实现双向绑定MVVM源码分析
vue双向绑定的原理及实现双向绑定MVVM源码分析 双向数据绑定的原理是:可以将对象的属性绑定到UI,具体的说,我们有一个对象,该对象有一个name属性,当我们给这个对象name属性赋新值的时候,新值 ...
- 最近老是有兄弟问我,Vue双向绑定的原理,以及简单的原生js写出来实现,我就来一个最简单的双向绑定,原生十行代码让你看懂原理
废话不多说直接看效果图 代码很好理解,但是在看代码之前需要知道Vue双向绑定的原理其实就是基于Object.defineProperty 实现的双向绑定 官方传送门 这里我们用官方的话来说Object ...
- Vue双向绑定实现原理demo
一.index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> ...
- vue双向绑定原理分析
当我们学习angular或者vue的时候,其双向绑定为我们开发带来了诸多便捷,今天我们就来分析一下vue双向绑定的原理. 简易vue源码地址:https://github.com/jiangzhenf ...
- Vue双向绑定原理及其实现
在之前面试的时候被面试官问到是否了解Vue双向绑定的原理,其实自己之前看过双向绑定的原理,但也就是粗略的了解,但是没有深入.面试官当时让我手写一个原理,但是就蒙了
- vue双向绑定原理源码解析
当我们学习angular或者vue的时候,其双向绑定为我们开发带来了诸多便捷,今天我们就来分析一下vue双向绑定的原理. 简易vue源码地址:https://github.com/maxlove123 ...
- 关于网上大量对Vue双向绑定的错误理解
对于Vue的双向绑定,现在基本是个前端都听说过,面试官也喜欢问这个问题.但对于Vue双向绑定的原理,掘金.博客园和segmentfault等技术社区充斥着大量的错误文章.这些文章的题目基本样子如下 “ ...
- Vue双向绑定原理,教你一步一步实现双向绑定
当今前端天下以 Angular.React.vue 三足鼎立的局面,你不选择一个阵营基本上无法立足于前端,甚至是两个或者三个阵营都要选择,大势所趋. 所以我们要时刻保持好奇心,拥抱变化,只有在不断的变 ...
- 梳理vue双向绑定的实现原理
Vue 采用数据劫持结合发布者-订阅者模式的方式来实现数据的响应式,通过Object.defineProperty来劫持数据的setter,getter,在数据变动时发布消息给订阅者,订阅者收到消息后 ...
随机推荐
- java访问https绕过证书信任
package com.xing.test; import java.io.BufferedReader; import java.io.IOException; import java.io.Inp ...
- GC线程是否为守护线程?
GC是垃圾收集的意思,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,从而有效的防止内存泄露.要请求垃圾收集,可以调用下面的方法之一:System.gc()或Runti ...
- python操作redis数据
一.环境安装 1.redispy安装 (automatic) C:\Users\Administrator>pip install redis 2.检测是否安装成功 (automatic) C: ...
- Perl 循环
Perl 循环 有的时候,我们可能需要多次执行同一块代码.一般情况下,语句是按顺序执行的:函数中的第一个语句先执行,接着是第二个语句,依此类推. 编程语言提供了更为复杂执行路径的多种控制结构. 循环语 ...
- Element-UI 的树列表实现单选
1. Element-UI 的 el-tree 组件当设置了 show-checkbox 属性以后,默认是只能多选的,如果我们想要将其改选为单选,就要进行一些特殊的处理,首先看效果图. 2. 组件代码 ...
- 暑假集训test-8-28
大概是从我一年以来做过的最傻逼的一套题了.. 一个半小时打完三个程序三个暴力拍完以为自己AK了,开心地耍了两个小时. 结果T3要写高精,LL炸了后4个点,中间还有个点是啥都不选的,我没用0去更新又炸了 ...
- NX二次开发-UFUN创建圆锥UF_MODL_create_cone1
NX11+VS2013 #include <uf.h> #include <uf_modl.h> UF_initialize(); //创建圆锥 UF_FEATURE_SIGN ...
- 移动端多选插件-jquery
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- Try running RemoteDll as Administrator
在使用RemoteDll注入动态库的时候发现注入有的动态库会提示下面的错误, LoadLibrary on remote process [1968 - Explorer.exe] failed. T ...
- Memory barrier,
A memory barrier, also known as a membar, memory fence or fence instruction, 是一种屏障指令,它使中央处理单元(CPU)或编 ...