任务描述
这是“动态数据绑定”的第三题。在第二题的基础上,我们再多考虑一个问题:”深层次数据变化如何逐层往上传播”。举个例子。
let app2 = new Observer({
name: {
firstName: 'shaofeng',
lastName: 'liang'
},
age: 25
});
app2.$watch('name', function (newName) {
console.log('我的姓名发生了变化,可能是姓氏变了,也可能是名字变了。')
});
app2.data.name.firstName = 'hahaha';
// 输出:我的姓名发生了变化,可能是姓氏变了,也可能是名字变了。
app2.data.name.lastName = 'blablabla';
// 输出:我的姓名发生了变化,可能是姓氏变了,也可能是名字变了。
观察到了吗?firstName 和 lastName 作为 name 的属性,其中任意一个发生变化,都会得出以下结论:”name 发生了变化。”这种机制符合”事件传播“机制,方向是从底层往上逐层传播到顶层。
这现象想必你们也见过,比如:“点击某一个DOM元素,相当于也其父元素和其所有祖先元素。”(当然,你可以手动禁止事件传播) 所以,这里的本质是:”浏览器内部实现了一个事件传播的机制”,你有信心自己实现一个吗?
所以重点是:深层次数据变化如何逐层往上传播
在任务二中,只能注册监听对象的第一层属性,深层属性的监听未完成。因为每一层的 event 都是独立的,深层对象属性触发的时候可以看出 this.events 里为空。所以要实现 event 之间的通信,使得可以向上传播。 一种方式: 每次进行 new Observer 的时候记录路径 set 时解析路径,虽然可以实现,但是也太残暴了,不符合向上传播的思想。
重点在于“冒泡”,让父级事件知道子级触发了事件,怎么实现事件冒泡呢,冒泡啊冒泡。也就是当触发子级事件时(也就是 set 方法里),能拿到父级对象,触发父级的 Event 对象的 emit 方法。所以思路就理清了,在创建对象的时候,记录父级对象,将父级对象传入子级中,再对属性路径进行整合解析,当触发set时进行冒泡,触发父级相应的事件(又是一个递归))。所以构造函数就需要多加两个参数,一个是路径 path,一个是父级对象 $parent。
最终代码(Demo)
1 | function Observer(data, path, $parent) { |