内容简介:js双向绑定
<input type="text" name="" value="" /> <span></span>
let mvvm = {};
Object.defineProperty(mvvm, 'hello', {
get: function() {
return document.getElementsByTagName("input")[0].value;
},
set: function(val) {
document.getElementsByTagName("input")[0].value = val;
document.getElementsByTagName('span')[0].innerHTML = val;
console.log("set被调用了,参数是:", val)
}
})
document.getElementsByTagName("input")[0].addEventListener('keyup', function(e) {
mvvm.hello = e.target.value;
})
这里利用了Object.defineProperty()里的getter setter方法,在修改mvvm对象上的hello属性时候,我们可以做一些事情,当触发set的时候,把input,span的值都修改成新的val,然后在input上监听 keyup
event, 触发keyup,将mvvm.hello设置为当前事件对象的value,同时触发了set,改变了input,span的值
问题来了
在上例中,我们只是监听了input的keyup事件,而且只是绑定了mvvm.如果有很多obj呢,如果不只是input呢,如果不只是input的keyup呢,所以我们需要做一个
通用的模式
Vue的数据绑定实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Two-way data-binding</title>
</head>
<body>
<div id="app">
<input type="text" v-model="text"> {{ text }}
</div>
<script>
function observe(obj, vm) {
Object.keys(obj).forEach(function(key) {
defineReactive(vm, key, obj[key]);
});
}
function defineReactive(obj, key, val) {
var dep = new Dep();
Object.defineProperty(obj, key, {
get: function() {
// 添加订阅者watcher到主题对象Dep
if (Dep.target) dep.addSub(Dep.target);
return val
},
set: function(newVal) {
if (newVal === val) return
val = newVal;
// 作为发布者发出通知
dep.notify();
}
});
}
function nodeToFragment(node, vm) {
var flag = document.createDocumentFragment();
var child;
while (child = node.firstChild) {
compile(child, vm);
flag.append(child); // 将子节点劫持到文档片段中
}
return flag;
}
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绑定的属性名
node.addEventListener('input', function(e) {
// 给相应的data属性赋值,进而触发该属性的set方法
vm[name] = e.target.value;
});
node.value = vm[name]; // 将data的值赋给该node
node.removeAttribute('v-model');
}
};
new Watcher(vm, node, name, 'input');
}
// 节点类型为text
if (node.nodeType === 3) {
if (reg.test(node.nodeValue)) {
var name = RegExp.$1; // 获取匹配到的字符串
name = name.trim();
new Watcher(vm, node, name, 'text');
}
}
}
function Watcher(vm, node, name, nodeType) {
Dep.target = this;
this.name = name;
this.node = node;
this.vm = vm;
this.nodeType = nodeType;
this.update();
Dep.target = null;
}
Watcher.prototype = {
update: function() {
this.get();
if (this.nodeType == 'text') {
this.node.nodeValue = this.value;
}
if (this.nodeType == 'input') {
this.node.value = this.value;
}
},
// 获取data中的属性值
get: function() {
this.value = this.vm[this.name]; // 触发相应属性的get
}
}
function Dep() {
this.subs = []
}
Dep.prototype = {
addSub: function(sub) {
this.subs.push(sub);
},
notify: function() {
this.subs.forEach(function(sub) {
sub.update();
});
}
};
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(id).appendChild(dom);
}
var vm = new Vue({
el: 'app',
data: {
text: 'hello world'
}
});
</script>
</body>
</html>
以上所述就是小编给大家介绍的《js双向绑定》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web Data Mining
Bing Liu / Springer / 2006-12-28 / USD 59.95
Web mining aims to discover useful information and knowledge from the Web hyperlink structure, page contents, and usage data. Although Web mining uses many conventional data mining techniques, it is n......一起来看看 《Web Data Mining》 这本书的介绍吧!