Vue之九数据劫持实现MVVM的数据双向绑定
vue是通过数据劫持的方式来做数据绑定的,其中最核心的方法便是通过Object.defineProperty()来实现对属性的劫持,达到监听数据变动的目的。
如果不熟悉defineProperty,猛戳这里
整理了一下,要实现mvvm的双向绑定,就必须要实现以下几点:
1、实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
4、mvvm入口函数,整合以上三者

1、实现Observer
我们知道可以利用Obeject.defineProperty()来监听属性变动
那么将需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter
这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化。。相关代码可以是这样:
var data = {name: 'kindeng'};
observe(data);
data.name = 'dmq'; // 监听到值变化了 kindeng --> dmq
function observe(data) {
if (!data || typeof data !== 'object') {
return;
}
// 取出所有属性遍历
Object.keys(data).forEach(function(key) {
defineReactive(data, key, data[key]);
});
};
function defineReactive(data, key, val) {
observe(val); // 监听子属性
Object.defineProperty(data, key, {
enumerable: true, // 可枚举
configurable: false, // 不能再define
get: function() {
return val;
},
set: function(newValue) {
console.log('哈哈哈,监听到值变化了 ', val, ' --> ', newValue);
val = newValue;
}
});
}
上面的思路整理中我们已经明确订阅者应该是Watcher, 而且var dep = new Dep();是在 defineReactive方法内部定义的,所以想通过dep添加订阅者
完整方法
function Observer(data) {
this.data = data;
this.walk(data);
} Observer.prototype = {
walk: function(data) {
var me = this;
Object.keys(data).forEach(function(key) {
me.convert(key, data[key]);
});
},
convert: function(key, val) {
this.defineReactive(this.data, key, val);
}, defineReactive: function(data, key, val) {
var dep = new Dep();
var childObj = observe(val);
Object.defineProperty(data, key, {
enumerable: true, // 可枚举
configurable: false, // 不能再define
get: function() {
if(Dep.target) {
dep.depend();
}
return val;
},
set: function(newVal) {
if(newVal === val) {
return;
}
val = newVal;
// 新的值是object的话,进行监听
childObj = observe(newVal);
// 通知订阅者
dep.notify();
}
});
}
}; function observe(value, vm) {
if(!value || typeof value !== 'object') {
return;
} return new Observer(value);
}; var uid = 0; function Dep() {
this.id = uid++;
this.subs = [];
} Dep.prototype = {
addSub: function(sub) {
this.subs.push(sub);
console.log(this.subs)
}, depend: function() {
Dep.target.addDep(this);
}, removeSub: function(sub) {
var index = this.subs.indexOf(sub);
if(index != -1) {
this.subs.splice(index, 1);
}
}, notify: function() {
this.subs.forEach(function(sub) {
sub.update();
});
}
}; Dep.target = null;
这里已经实现了一个Observer了,已经具备了监听数据和数据变化通知订阅者的功能,那么接下来就是实现Compile了
2、实现Compile
compile主要做的事情是解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图,如图所示:

因为遍历解析的过程有多次操作dom节点,为提高性能和效率,会先将跟节点el转换成文档碎片fragment进行解析编译操作,解析完成,再将fragment添加回原来的真实dom节点中
3、实现Watcher
Watcher订阅者作为Observer和Compile之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(dep)里面添加自己
2、自身必须有一个update()方法
3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
实例化Watcher的时候,调用get()方法,通过Dep.target = watcherInstance标记订阅者是当前watcher实例,强行触发属性定义的getter方法,getter方法执行的时候,就会在属性的订阅器dep添加当前watcher实例,从而在属性值有变化的时候,watcherInstance就能收到更新通
4、实现MVVM
MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
知。
function MVVM(options) {
this.$options = options;
var data = this._data = this.$options.data, me = this;
// 属性代理,实现 vm.xxx -> vm._data.xxx
Object.keys(data).forEach(function(key) {
me._proxy(key);
});
observe(data, this);
this.$compile = new Compile(options.el || document.body, this)
}
MVVM.prototype = {
_proxy: function(key) {
var me = this;
Object.defineProperty(me, key, {
configurable: false,
enumerable: true,
get: function proxyGetter() {
return me._data[key];
},
set: function proxySetter(newVal) {
me._data[key] = newVal;
}
});
}
};
这里主要还是利用了Object.defineProperty()这个方法来劫持了vm实例对象的属性的读写权,使读写vm实例的属性转成读写了vm._data的属性值
Vue之九数据劫持实现MVVM的数据双向绑定的更多相关文章
- Vue中MVVM模式的双向绑定原理 和 代码的实现
今天带大家简单的实现MVVM模式,Object.defineProperty代理(proxy)数据 MVVM的实现方式: 模板编译(Compile) 数据劫持(Observer) Object ...
- Blazor和Vue对比学习(基础1.5):双向绑定
这章我们来学习,现代前端框架中最精彩的一部分,双向绑定.除了掌握原生HTML标签的双向绑定使用,我们还要在一个自定义的组件上,手撸实现双向绑定.双向绑定,是前两章知识点的一个综合运用(父传子.子传父) ...
- [Vue]组件——.sync 修饰符实现对prop 进行“双向绑定”
一.同时设置1个 prop 1.以 update:my-prop-name 的模式触发事件,如对于title属性: this.$emit('update:title', newTitle) 2.然后父 ...
- 简简单单的Vue1(MVVM与Vue的双向绑定原理)
既然选择了远方,便只顾风雨兼程 __ HANS许 系列:零基础搭建前后端分离项目 系列:零基础搭建前后端分离项目 Vue 在此之前的文章我们讲述了前端开发的工具,语言的知识,接下来我们从头开始学习一个 ...
- vue实现数据双向绑定的原理
一.知识准备Object.defineProperty( )方法可以直接在一个对象上定义一个新属性,或者修改一个已经存在的属性,并返回这个对象.Object.defineProperty(obj,pr ...
- MVVM以及vue的双向绑定
原文:https://www.cnblogs.com/onepixel/p/6034307.html MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式,其核 ...
- ES6入门:数据劫持、Proxy、Reflect
什么是数据劫持 Object数据劫持实现原理 Array数据劫持的实现原理 Proxy.Reflect 一.什么是数据劫持 定义:访问或者修改对象的某个属性时,在访问和修改属性值时,除了执行基本的数据 ...
- Vue双向绑定原理,教你一步一步实现双向绑定
当今前端天下以 Angular.React.vue 三足鼎立的局面,你不选择一个阵营基本上无法立足于前端,甚至是两个或者三个阵营都要选择,大势所趋. 所以我们要时刻保持好奇心,拥抱变化,只有在不断的变 ...
- vue双向绑定原理及实现
vue双向绑定原理及实现 一.总结 一句话总结:vue中的双向绑定主要是通过发布者-订阅者模式来实现的 发布 订阅 1.单向绑定和双向绑定的区别是什么? model view 更新 单向绑定:mode ...
随机推荐
- JavaScript的预编译和执行
JavaScript引擎,不是逐条解释执行javascript代码,而是按照代码块一段段解释执行.所谓代码块就是使用<script>标签分隔的代码段. 整个代码块共有两个阶段,预编译阶段和 ...
- 6.1 MSI/MSI-X Capability结构
PCIe设备可以使用MSI或者MSI-X报文向处理器提交中断请求,但是对于某个具体的PCIe设备,可能仅支持一种报文.在PCIe设备中含有两个Capability结构,一个是MSI Capabilit ...
- Linux下搭建SVN服务器遇到的问题及解决方法,
1.checkout时,提示:URL svn://192.168.1.99/svntest doesn't exist... 奇怪,怎么会提示库不存在呢?肯定是哪里配置问题.后来尝试了半天,也在网上搜 ...
- FusionCharts 2D帕累托图
1.了解帕累托图的特性以及和其他图的共性 2.设计帕累托图页面中引入图的类型以及怎么引入到页面 Pareto2D.html: <!DOCTYPE HTML PUBLIC "-//W3C ...
- VxWorks程序指南
******************************************* 一.任务 ******************************************* 任务状态:挂起 ...
- GJB150-2009军用装备实验室环境试验方法新版标准
http://www.kekaoxing.com/m/view.php?aid=22604 GJB150.1A-2009 军用装备实验室环境试验方法第1部分:通用要求(代替GJB150.1-86)GJ ...
- Redis进阶实践之十五 Redis-cli命令行工具使用详解第二部分(结束)
一.介绍 今天继续redis-cli使用的介绍,上一篇文章写了一部分,写到第9个小节,今天就来完成第二部分.话不多说,开始我们今天的讲解.如果要想看第一篇文章,地址如下:http: ...
- 在TextBox中敲击回车执行ASP.NET后台事件
1.在TextBox中敲击回车执行ASP.NET后台事件 0.说明 页面中有一个用于搜索的TextBox,希望能在输入内容后直接回车开始搜索,而不是手动去点击它旁边的搜索按钮 但因为该TextBo ...
- ASP.NET VS2013 Office 转 PDF
本文适用于VS2013 项目中的Word转换为PDF.Excel转换为PDF.PPT转换为PDF 0.一种更加简单方便的方法 1.本页所用的方法在本机测试时基本不会出现问题,只是偶尔PPT转PDF失败 ...
- Oracle11g客户端client的下载与安装
下载地址: http://www.oracle.com/technetwork/database/enterprise-edition/downloads/112010-win64soft-09446 ...