学习VUE 实现简单的双向数据绑定的原理
在学习Vue的过程中,了解数据双向绑定的原理很重要,这是Vue中 实现MVVM的基本原理
Vue中 它既是数据的劫持者也是观察者也是消息发布者 背后数据的驱动与展示 调用的是其背后数据双向绑定的结果
下面是简单实现双向绑定原理的代码
HTML中 绑定属性的节点
HTML中 绑定属性的节点
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<div id="app">
<div data-on="count"></div>
<div data-on="data"></div>
<div data-on="data"></div>
<div data-on="data"></div>
<div data-on="data"></div>
<div data-on="message"></div>
<input i-model="message" type="text" name="" id="" />
</div>
<script src="./index.js"></script>
</body>
</html>
class initObj {
constructor({ el, data }) {
this.$el = document.querySelector(el); //获取挂载的节点
this.$data = data(); //获取传输的数据
this.$ob = this.creatObserver(); //创建一个OB观察器
this.defineProperty(); //初始化数据背后的 set和get方法
}
creatObserver() {
const that = this;
return {
Observer: {
maps: {}, //保存属性与节点之间的映射关系
add(k, cb) {
if (this.maps[k]) {
this.maps[k].push(cb);
return;
}
this.maps[k] = [cb];
} //用于添加属性和节点映射关系的方法
},
subscribe(k) {
//这是订阅消息的方法
that.$el.querySelectorAll(`[data-on=${k}]`).forEach(el => {
const cb = text => (el.innerHTML = text);
this.Observer.add(k, cb); //找到属性对用的节点 调用ADD方法保存映射关系
}); //查找当前属性与之对应的节点 只是一对多的关系
that.$el.querySelectorAll(`[i-model=${k}]`).forEach(el => {
const cb = text => (el.value = text); // 创建一个改变节点信息的方法 text 是改变之后的数据 el是节点
this.Observer.add(k, cb);
el.addEventListener("input", function (e) {
that[k] = e.target.value;
});
});
this.emit(k); //映射关系保存完后 调用发布消息的方法 把当前的k传过去
},
emit(k) {
// 这是发布消息的方法
this.Observer.maps[k].forEach(cb => cb(that[k])); //拿到传过来的K 找到当前K对应的改变节点的cb方法
}
};
}
defineProperty() {
for (let k in this.$data) {
Object.defineProperty(this, k, {
get() {
return this.$data[k];
},
set(newValue) {
this.$data[k] = newValue;
this.$ob.emit(k); //set方法调用后 数据已经更新 把当前更新的K传给 emit(发布消息 方法)更新内容
}
});
this.$ob.subscribe(k);
}
console.log(this);
}
}
const app = new initObj({
el: "#app",
data() {
return {
count: 10,
data: 20,
message: "helleoword"
};
}
});