网上有很多关于数据的双向绑定的介绍,但是感觉描述的太过于累赘。使阅读者感觉太难理解。这里我将一步一步循循渐进的方式。领导你们写一个数据的双向绑定的案例。 ——观察者模式
数据单向绑定M——V或者V——M
数据单向绑定之数据驱动视图即 M——V
<input id="test1">
</input>
<script>
let data = 2;
const oSpan = document.getElementById("test1");
oSpan.value = data;
// 这里改变数据通知视图变化
setInterval(() => {
data += 1;
oSpan.value = data;
}, 1000)
</script>
数据单向绑定之视图驱动数据即 V——M
<input id="dom2"/>
</body>
<script>
let data;
const oDom = document.getElementById("dom2")
// 通过监听 dom变化通知数据改变
oDom.addEventListener("input", (ev) => {
data = ev.target.value
console.log(data)
})
</script>
从上面的案例我们得知要想数据改变;我们需要获取变化,通知目标。
得到的思想:
1 需要一个观察者:收集数据或者dom的变化
2 需要一个订阅者:获取改变并更新数据或者dom
数据之双向绑定实现 MVVM
根据上面我们得到的启示来一步一步实现。
这里你需要了解一下:Object.defineProperty
数据双绑定一 观察者
案例只是单成对象,并没有做for循环遍历
<script>
const obj = {
name: 'yx',
age: 18
};
Object.defineProperty(obj, "name", {
enumerable: true,
configurable: true,
get: function (val) {
console.log("这里要添加订阅者")
},
set: function (val) {
console.log("这里要通知订阅者")
}
});
// 读取数据的时候 我们要添加订阅
setTimeout(() => {
console.log(obj.name)
}, 1000)
// 改变数据的时候通知
setTimeout(() => {
obj.name = "yxx"
}, 3000)
</script>
数据双绑定二 订阅者
// 订阅者通过订阅器添加
function Watcher() {
setTimeout(() => {
// 这里是为了触发defineProperty 添加订阅者
this.get()
}, 5000)
}
Watcher.prototype = {
// dom更新
update: function () {
console.log("dom要更新")
},
// 促使添加订阅者
get: function () {
Dep.target = this; // 这样处理很方便添加订阅者,需自己体会
const val = obj.name;
console.log(`我要获取${val}触发添加订阅者`)
}
};
数据双绑定三 订阅器
把订阅者和观察者联合起来
// 订阅器
function Dep() {
this.subs = []
}
Dep.prototype = {
// 添加订阅者
addSub: function (sub) {
this.subs.push(sub)
},
// 通知订阅者
notify: function () {
this.subs.forEach(function (sub) {
sub.update();
});
}
};
数据双绑定实例 测试
<script>
const obj = {
name: 'yx',
age: 18
};
// 订阅器 添加/通知 订阅者
function Dep() {
this.subs = []
}
Dep.prototype = {
addSub: function (sub) {
this.subs.push(sub)
},
notify: function () {
this.subs.forEach(function (sub) {
sub.update();
});
}
};
dep = new Dep();
function Observer(data, key) {
Object.defineProperty(obj, "name", {
enumerable: true,
configurable: true,
get: function (val) {
console.log("这里要添加订阅者");
// dep.addSub(objW)
dep.addSub(Dep.target)
},
set: function (val) {
console.log("这里要通知订阅者")
dep.notify()
}
});
}
observer = new Observer(obj, "name");
function Watcher() {
setTimeout(() => {
this.get()
}, 5000)
}
Watcher.prototype = {
// dom更新
update: function () {
console.log("dom要更新")
},
// 促使添加订阅者
get: function () {
Dep.target = this;
const val = obj.name;
console.log("我要获取数据触发添加订阅者")
}
};
new Watcher()
setTimeout(() => {
obj.name = "yxxx"
}, 10000)
</script>
若要对多层对象监听则可以对对象实现for循环对每一个属性进行监听