对象代理,双向绑定的简单实现
2019-03-14 本文已影响0人
D_R_M
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MVVM</title>
</head>
<body>
<div id="app">
<div>{{msg}},{{name}},{{msg}}</div>
<span>span 后 -》 {{name}}</span>
<div>{{msg}}
<div>
<div></div>
</div>
</div>
{{name}}
<input type="text" c-model="name"/>
</div>
<script>
;(function (window,document) {
var MVVM = function(obj){
if(!(this instanceof MVVM)) return new MVVM(obj);
this.$el = document.querySelector(obj.el);
Object.defineProperty(this,'$data',{
value:obj.data,
enumerable: false,
configurable: true
})
Object.keys(this.$data).forEach(function(item){
this.$data[item]=new ViewModel(this.$data[item],this);//双向绑定
Object.defineProperty(this,item,{//对象代理
enumerable: true,
configurable: true,
set:function(val) {
this.$data[item].setVal(val);
},
get:function() {
return this.$data[item].getVal();
}
})
}.bind(this));
this.init(this.$el);
}
MVVM.prototype.init=function(elment){
var el = elment;
var fragment = document.createDocumentFragment();
var childNode;
while (childNode = el.firstChild){
fragment.appendChild(childNode);
}
this.replace(fragment.childNodes);
Object.keys(this.$data).forEach((item)=>{
this.$data[item].updates();
})
el.appendChild(fragment);
}
MVVM.prototype.replace =function(fragmentContent){
Array.prototype.slice.call(fragmentContent).forEach(item=>{
if(item.nodeType === 1){
Array.from(item.attributes).forEach(attr=>{
if(attr.name.indexOf('c-') >= 0){
this.$data[attr.value].bindNode(item);
item.removeAttribute(attr.name);
item.addEventListener('input',function (e) {
this.$data[attr.value].setVal(e.target.value);
}.bind(this))
}
});
if(item.childNodes.length>0){
this.replace(item.childNodes);
}
}else if(item.nodeType === 3){
var reg = /\{\{([^\}]+)\}\}/g;
if(reg.test(item.textContent)){
item.textContent.replace(reg,function () {
item.bindc=item.textContent;
this.$data[arguments[1]].bindNode(item);
}.bind(this));
}
}
})
}
var ViewModel =function(data,mvvm) {
this.data = data;
this.nodes = [];
this.mvvm = mvvm;
}
ViewModel.prototype.bindNode=function (node) {
this.nodes.push(node);
}
ViewModel.prototype.updates = function () {
this.nodes.forEach(item=>{
if(item.nodeType === 1 && item.nodeName =='INPUT'){
item.value = this.data;
}else{
var reg = /\{\{([^\}]+)\}\}/g;
item.textContent = item.bindc.replace(reg,function(){
return this.mvvm.$data[arguments[1]].data
}.bind(this))
}
})
}
ViewModel.prototype.setVal = function (newVal) {
if(newVal !== this.data){//值有改变 才做 修改
this.data = newVal;
this.updates();
}
}
ViewModel.prototype.getVal = function () {
return this.data;
}
window.MVVM = MVVM;
})(window,document);
var mv = MVVM({
el:'#app',
data:{
msg:'我是msg',
name:'我是name'
}
});
</script>
</body>
</html>