ES6的Proxy对象可以用来拦截一个Object对象的属性的修改,这次我们利用它来实现一个简单的双向绑定。
废话不多说,请看代码。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>View to model</title>
</head>
<body>
<div>
<!-- 使用'bind-to'的属性来标记这个输入框里的值会对Model里的属性进行修改 -->
<input bind-to="name" />
<input bind-to="name" />
</div>
<!-- 使用#属性名#来把Model里的值映射到DOM中 -->
<span>#name#</span>
<span>#name#</span>
<button onclick="reset()">reset</button>
<script type="text/javascript">
var handler = {
// 拦截属性的设置,触发试图的更新
set: function(target, key, value, receiver) {
target[key] = value;
updateView(propertyName);
return Reflect.set(target, key, value);
},
};
// 双向绑定的对象
var model = new Proxy({}, handler);
// 双向绑定列表
var inputs = {},views = {};
var all = document.all;
// 遍历所有DOM元素
for(var i=0,l=all.length;i<l;i++){
// 找到所有有bind-to的输入框
if(all[i].getAttribute('bind-to')){
var dom = all[i];
var propertyName = dom.getAttribute('bind-to');
inputs[propertyName] = inputs[propertyName] ? inputs[propertyName] : [];
views[propertyName] = views[propertyName] ? views[propertyName] : [];
inputs[propertyName].push(dom);
dom.addEventListener('change',function function_name(e) {
var propertyName = e.target.getAttribute('bind-to');
model[propertyName] = e.target.value;
})
}
// 找到所有model驱动的页面元素
if(all[i].innerHTML && all[i].innerHTML.length>2 &&
all[i].innerHTML[0] == '#' &&
all[i].innerHTML[all[i].innerHTML.length-1] == '#'){
var propertyName = all[i].innerHTML.slice(1,all[i].innerHTML.length-1);
inputs[propertyName] = inputs[propertyName] ? inputs[propertyName] : [];
views[propertyName] = views[propertyName] ? views[propertyName] : [];
views[propertyName].push(all[i]);
}
}
// 更新View
function updateView(propertyName) {console.log('update ' + propertyName);
if(views[propertyName]){
for(var i = 0,l = views[propertyName].length;i < l;i++){
views[propertyName][i].innerText = model[propertyName];
}
}
if(inputs[propertyName]){
for(var i = 0,l = inputs[propertyName].length;i < l;i++){
inputs[propertyName][i].value = model[propertyName];
}
}
}
function reset() {
for(var name in model){
model[name] = '';
}
}
</script>
</body>
</html>