vue数据双向绑定的原理及其实现

第一次写,CSDN博客,希望这篇文章对大家的学习有所帮助,同时大家感觉有什么不满意的欢迎大家提出宝贵的意见。这篇文章简单的说一下vue.js中数据绑定的原理,以及怎样用代码去实现一个数据双向绑定

vue中数据双向绑定原理

vue实现双向绑定的原理是数据劫持结合发布订阅模式和Object.defineProperty中的get和set方法实现的。

自己实现一个数据双向绑定

主要思路是先的定义一个对象这里就叫myVue吧,然后进行数据劫持(observer),然后对数据进行编译(Compile),再结合发布订阅模式将observer和Compile联系进来,最后实现数据双向绑定
1、定义一个myVue对象。

这里没什么说的,直接申明一个对象就行。这个对象接受一个对象参数,其中包括el用于指明 myVue 实例的挂载目标,data数据.
2、数据劫持。

主要是对data中的数据进行劫持。这里就用到了Object.defineProperty的get获取data中的数据和set对数据进行重新赋值,observer的实现下边贴出代码供大家参考
vue数据双向绑定的原理及其实现
3.编译。

数据编译是通过document.createDocumentFragment()创建一个文档碎片,把所有的新节点附加其上,然后把文档碎片的内容一次性添加到el中,然后将el中的{{}}中的内容和data的数据进行相对应的替换。
vue数据双向绑定的原理及其实现
vue数据双向绑定的原理及其实现
4.结合发布订阅者模式让observer和Compile建立联系

具体实现直接上代码。
发布订阅
vue数据双向绑定的原理及其实现
watch
vue数据双向绑定的原理及其实现
然后在observer和Compile分别进行发布订阅和监听。
5,实现数据双向绑定。
这一步的操作主要在Compile中,在有v-model的输入框中的值再data中找到然后赋值给输入框的value,然后同输入框的input对data中对应的值进行改变。
vue数据双向绑定的原理及其实现
这样一个数据双向绑定的功能就实现了下面我贴出全部代码供大家参考。
function Vue(options={data:{}}){
this.options = options;
const data = this._data =options.data;
observer(data);
//将data的值赋值到this上
for (let key in data) {
Object.defineProperty(this, key, {
enumerable:true,
get(){
return this._data[key]
},
set(newVal){
if(this._data[key] === newVal){
return;
}
this._data[key]=newVal
}
})
}
new Compile(options.el,this);
}
//编译
function Compile(el,vm){
vm.doc=document.querySelector(el);letfragment=document.createDocumentFragment();while(child=vm.doc = document.querySelector(el); let fragment = document.createDocumentFragment(); while (child = vm.doc.firstChild){
fragment.appendChild(child);
}
replace(fragment);
function replace(fragment){
Array.from(fragment.childNodes).forEach(function(node){
let text = node.textContent;
let reg = /{{(.*)}}/;
if(node.nodeType =3&&reg.test(text)){
let arr = RegExp.$1.split(’.’);
let val = vm;
arr.forEach(function(k){
val =val[k];
})
new Watch(vm,RegExp.KaTeX parse error: Expected 'EOF', got '}' at position 124: …e(reg,val); }̲ if(node.nod…doc.appendChild(fragment);
}
//数据劫持
function Observer(data){
let dep= new Dep();
for (let key in data) {
let val= data[key];
observer(val);
Object.defineProperty(data , key , {
enumerable : true,
get(){
Dep.target&&dep.addSub(Dep.target);
return val;
},
set(newVal){
if (newVal === val) {
return;
}
val=newVal;
observer(newVal);
dep.notify();
}
})
}
}
function observer(data){
if(typeof data !
“object”) return;
return new Observer(data);
}
//发布订阅
function Dep(sub){
this.sub = [];
}
Dep.prototype.addSub = function(sub){
this.sub.push(sub);
}
Dep.prototype.notify = function(){
this.sub.forEach(function(sub){
sub.update();
})
}
//watch
function Watch (vm,reg,fn) {
this.vm = vm;
this.reg = reg;
this.fn = fn;
Dep.target =this;
let val =this.vm;
let arr = this.reg.split(’.’);
arr.forEach(function(k){
val = val[k];
})
Dep.target = null;
}
Watch.prototype.update = function() {
let val =this.vm;
let arr = this.reg.split(’.’);
arr.forEach(function(k){
val = val[k];
})
this.fn(val);
}