1.遍历dom树解析指令,寻找事件对应的属性名。
2.将属性名分类存储在订阅者信息中,并根据不同的dom生成对应的watch实例。
3.将数据绑定在视图上。
4.将视图数据更新到对应的watch实例。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MVVM</title>
<script>
// 实现基本架构
// 把模型的数据显示到视图
// 把视图上的修改更新到模型上
// 订阅数据变化,绑定更新,添加订阅者
// 发布者
class Vue {
constructor(options){
this.options = options;
this.$data = options.data; // 获取数据
this.$el = document.querySelector(options.el); // 获取对象
this._directives = {} // 存放订阅者
this.Observer(this.$data);
this.Compile(this.$el);
}
// 劫持数据
Observer(data){
for (let key in data){
this._directives[key] = [];
let Val = data[key]
let _this = this._directives[key]
Object.defineProperty(this.$data, key, {
get: function(){
return Val;
},
set: function(newVal){
if (newVal !== Val) {
Val = newVal;
// 遍历订阅者实例,更新视图
_this.forEach( watch => {
watch.update();
})
}
}
});
}
}
// 解析指令
Compile(el){
let nodes = el.children;
for (let i = 0; i < nodes.length; i++) {
let node = nodes[i];
if (node.children.length) {
this.Compile(node);
}
if (node.hasAttribute("v-text")) {
let attrVal = node.getAttribute("v-text");
this._directives[attrVal].push(new Watcher(node, attrVal, this, 'innerHTML'));
}
if (node.hasAttribute("v-model")) {
let attrVal = node.getAttribute("v-model");
this._directives[attrVal].push(new Watcher(node, attrVal, this, 'value'));
let _this = this;
node.addEventListener("input", (function(){
return function(){
// 更新视图同步到模型
_this.$data[attrVal] = node.value;
}
})());
}
}
}
}
// 订阅者
class Watcher {
constructor(el, vm, mySelf, attr){
this.el = el; // 事件Dom
this.vm = vm; // 绑定属性名
this.mySelf = mySelf; // Vue实例
this.attr = attr;
this.update(); // 初始化数据
}
update(){
this.el[this.attr] = this.mySelf.$data[this.vm];
}
}
</script>
</head>
<body>
<div id="app">
<h1>数据响应式</h1>
<div>
<div v-text="myText"></div>
<div v-text="myBox"></div>
<input type="text" v-model="myBox">
</div>
</div>
<script>
const app = new Vue({
el: "#app",
data: {
myText: "大吉大利,今晚吃鸡!",
myBox: '局部'
}
})
</script>
</body>
</html>
网友评论