百度前端技术学院---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;
}	


posted @ 2017-03-03 20:33  ABC君  阅读(180)  评论(0编辑  收藏  举报