JSFiddle - React, Tailwind, and code Playground
by ruirui
HTML
<div>
Vue 动态数据绑定(三)
</div>
<div>
请打开控制台查看
</div>
JavaScript
function Observer(data, path, $parent) {
this.data = data;
this.$parent = (typeof $parent === 'undefined') ? null : $parent;
this.makeObserver(data, path);
this.eventsBus = new Event();
}
Observer.prototype.makeObserver = function(data, path) {
var self = this;
for (var i in data) {
if (data.hasOwnProperty(i)) {
var new_path = (typeof path === 'undefined') ? i : (path + '.' + i);
if (typeof data[i] === 'object') {
new Observer(data[i], new_path, self);
} else {
this.getset(i, data[i], new_path);
}
}
}
}
Observer.prototype.getset = function (i, value, path) {
let val = value;
let self = this;
Object.defineProperty(this.data, i, {
configurable: true,
enumerable: true,
get: function () {
console.log('你访问了' + i);
return val;
},
set: function (newval) {
self.bubble(self, path, val, newval); // 事件冒泡
if(typeof newval === 'object') {
new Observer(val);
}
console.log('你设置了' + i + ',新的值为' + newval);
val = newval;
}
})
}
// 往上层传递 沿着父对象往上传递
Observer.prototype.bubble = function (self, path, val, newval) {
if (self === null)
return;
self.eventsBus.emit(path, val, newval);
var parent_path = path.split('.').slice(0, -1).join('.'); // 拆出父级的路径
self.bubble(self.$parent, parent_path, val, newval); //关键点 递归触发父级的emit
}
function Event() {
this.events = {};
}
Event.prototype.on = function (attr, callback) {
if (this.events[attr]){
this.events[attr].push(callback);
} else {
this.events[attr] = [callback];
}
}
Event.prototype.emit = function (attr, val, newval) {
this.events[attr] && this.events[attr].forEach(function(item) {
item(newval);
})
}
Observer.prototype.$watch = function (attr,callback){
// 注册一个监听事件
this.eventsBus.on(attr, callback);
}
let app1 = new Observer({
age: 25,
name: {
firstName: 'rui',
lastName: 'sun'
}
})
app1.$watch('age', function(age) {
...