您的位置:首页 > 产品设计 > UI/UE

vue.js双向数据绑定实现原理

2017-10-01 11:44 1471 查看
源码如下:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="text" v-model="text">
{{text}}
</div>
<script>
/*var dom = nodeToFragment(document.getElementById('app'));
console.log(dom);*/

function compile(node,vm) {
var reg =/\{\{(.*)\}\}/;

//节点类型为元素
if(node.nodeType === 1){
var attr = node.attributes;

//解析属性
for(var i=0;i<attr.length;i++){
if(attr[i].nodeName = 'v-model'){
var name = attr[i].nodeValue;//获取v-model绑定的属性名

//放在该位置原因是获取name值
node.addEventListener('input',function (e) {
//给相应的data属性赋值,进而触发该属性的set方法
vm[name]=e.target.value;
});
node.value = vm[name];
node.removeAttribute('v-model');
}
};
}

//节点类型为text
if(node.nodeType === 3){
if(reg.test(node.nodeValue)){
var name = RegExp.$1;//1.获取匹配到的字符串
name = name.trim();
//node.nodeValue = vm[name];//将data的值赋值给该node

new Watcher(vm,node,name);
}
}
}

function nodeToFragment(node,vm) {
var flag = document.createDocumentFragment();
var child;
while(child = node.firstChild){
compile(child,vm);
flag.append(child);
}
return flag;
}

function defineReactive(obj,key,val) {
var dep = new Dep();

Object.defineProperty(obj,key,{
get:function () {
if(Dep.target) dep.addSub(Dep.target);
return val;
},
set:function (newVal) {
if(newVal===val) return ;
val = newVal;
//console.log(val);
//作为发布者发出通知
dep.notify();
}
});
}
function observe(obj,vm) {
Object.keys(obj).forEach(function (key) {
defineReactive(vm,key,obj[key]);
})
}

function Vue(options) {
this.data = options.data;
var data = this.data;
observe(data,this);

var id = options.el;
var dom = nodeToFragment(document.getElementById(id),this);

//编译完成后,将dom返回到app中
document.getElementById('app').appendChild(dom);
}
function Dep() {
this.subs = [];
}
Dep.prototype={
addSub:function (sub) {
this.subs.push(sub);
},
notify:function () {
this.subs.forEach(function (sub) {
sub.update();
});
}
}
function Watcher(vm,node,name) {
Dep.target = this;
this.name = name;
this.node = node;
this.vm = vm;
this.update();
Dep.target=null;
}
Watcher.prototype={
update:function () {
this.get();
this.node.nodeValue = this.value;
},
//获取data中的属性值
get:function () {
this.value = this.vm[this.name];//触发相应属性的get
}
};
var vm = new Vue({
el:'app',
data:{
text:'hello world'
}
});
</script>
</body>
</html>


参考:http://www.jb51.net/article/99129.htm
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: