百度前端技术学院---vue动态数据绑定-3
回调中如何实现冒泡?
/*
通过将记录每个属性的父级,当属性值变化,逐级寻找回调
最开始,打算在data上附加父级信息,后来感觉头快爆炸了,实现太麻烦,无法通过属性来获取父级对象名字,
最后想到元素的parentNode , 不需要做成链式的,每个子属性,只需要记住它的父元素就行了.
*/
(function(){
window.Observer = function(data){
this.data=data;
this.makeObserver();
};
var oP = Observer.prototype;
oP.watchArr = {};
//保存父级信息
oP._parentNode = {};
//父级初始化为空
oP._parent = '';
oP.makeObserver = function(){
for(var key in this.data){
if(!this.data.hasOwnProperty(key))return;
var val = this.data[key];
//设置父级表
this._parentNode[key] = this._parent;
if(typeof val === 'object'){
oP._parent = key;
//递归时将当前key设置为父级
new Observer(val);
};
this.setObserver(val,key);
};
};
oP.setObserver = function(val,key){
var that = this;
Object.defineProperty(that.data,key,{
enumerable: true,
configurable: true,
get:function(){
return val;
},
set:function(newValue){
if(typeof newValue === 'object'){
new Observer(newValue);
};
if(val === newValue)return;
//触发set时,执行冒泡
oP.bubbleWatch(key,newValue,val);
val = newValue;
}
});
};
oP.bubbleWatch = function(key,newValue,val){
if(this.watchArr[key]){
//如果监听表存在key,执行一次
this.implementWatch(key,newValue,val);
//如果冒泡选项为false,则return
if(!this.watchArr[key].options.bubble)return;
};
//剩下冒泡为true的,递归调用父级属性的回调
parentKey = this.getParent(key);
if(parentKey)this.bubbleWatch(parentKey,newValue,val);
};
oP.getParent = function(key){
var parent = this._parentNode[key];
return parent;
};
oP.implementWatch = function(key,newValue,val){
for(var i = 0;i<this.watchArr[key].fn.length;i++){
this.watchArr[key].fn[i](newValue,val);
}
};
oP.$watch = function(key,fn,options){
options = extend(options,{
bubble:false
});
if(!this.watchArr[key]){
this.watchArr[key]={
options:options,
fn:[]
};
};
this.watchArr[key].fn.push(fn);
return this;
};
})()
var app2 = new Observer({
name: {
firstName: 'xiao',
lastName: {
ming:"ming",
liang:"liang"
}
},
age: 25
});
app2.$watch('name', function (newName) {
console.log("name",newName)
});
app2.$watch('firstName', function (newName) {
console.log('firstName',newName)
},{bubble:true});
app2.$watch('ming', function (newName) {
console.log('ming',newName)
});
app2.data.name.firstName = 'll';
app2.data.name.firstName = 'lll';
app2.data.name.lastName.ming = 'hong';
/*
输出:
firstName ll ---触发watch
name ll --- 冒泡到name上触发name的回调函数
firstName lll
name lll
ming hong --- 没有冒泡,所以未触发name上的回调
*/
function extend(x,y){
var y=y||{};
for(var i in x){
if(typeof x[i] === "object"){
y[i] = (x[i] instanceof Array) ? [] : {};
extend(x[i],y[i])
}else {
y[i] = x[i];
}
};
return y;
}