MVVM之数据劫持

  • A+
所属分类:javascript JS框架

在线测试

		
"use strict";
function MVVM(data){
	var data = this.$data = data,
		me = this;
	this.$watch = function(exp, cb){
		return new Watcher(me, exp, cb);
	};
	Object.keys(data).forEach(function(key){
		me._proxy(key);
	});
	new Observer(data, this);
};
MVVM.prototype = {
	_proxy : function(key){
		var me = this;
		Object.defineProperty(me, key, {
			configurable : false,
			enumerable : true,
			get : function(){
				return me.$data[key];
			},
			set : function(val){
				me.$data[key] = val;
			}
		})
	}
};
function Observer(data, self){
	this.data = data;
	this.mvvm = self;
	this.walk(data);
};
Observer.prototype = {
	walk : function(data){
		var me = this;
		Object.keys(data).forEach(function(key){
			me.convert(key, data[key]);
		});
	},
	convert : function(key, val){
		this.defineReactive(this.data, key, val);
	},
	defineReactive : function(obj, key, val){
		var me = this,
			dep = new Dep(),
			childObj = observer(val);
		Object.defineProperty(obj, key, {
			enumerable : true,
			configurable : false,
			get : function(){
				if(Dep.target) dep.depend(dep);
				return val;
			},
			set : function(newVal){
				if(val === newVal) return;
				childObj = observer(newVal);
				val = newVal;
				dep.notify();
			}
		})
	}
};
function observer(val){
	if(!val || typeof val !== 'object') return;
	return new Observer(val);
};
const Dep = (function(){
	var UUID = 0;
	return function(){
		this.UUID = UUID++;
		this.subs = [];
	}
})();
Dep.target = null;
Dep.prototype = {
	depend : function(dep){
		Dep.target.addDeps(dep);
	},
	addSub : function(sub){
		this.subs.push(sub);
	},
	notify : function(){
		this.subs.forEach(function(sub){
			sub.updata();
		});
	}
};
function Watcher(vm, exp, cb){
	this.cb = cb;
	this.vm = vm;
	this.exp = exp;
	this.depIds = {};
	this.value = this.get();
};
Watcher.prototype = {
	addDeps : function(dep){
		if( !this.depIds.hasOwnProperty(dep.uuid) ){
			dep.addSub(this);
			this.depIds[dep.uuid] = dep;
		}
	},
	get : function(){
		Dep.target = this;
		var value = this.vm[this.exp];
		Dep.target = null;
		return value;
	},
	updata : function(){
		this.run();
	},
	run : function(){
		var newVal = this.get(),
			oldVal = this.value;
		if(newVal !== oldVal){
			this.cb.call(this, newVal, oldVal);
			oldVal = newVal;
		}
	}
};
var o = {name:'LXY', age:'24'};
var vm = new MVVM(o);
vm.$watch('name', function(newVal, oldVal){
	console.log([newVal, oldVal]);
});
vm.$watch('age', function(newVal, oldVal){
	console.log([newVal, oldVal]);
});
vm.name = 'ASD';
vm.age = '10';
weinxin
我的微信
欢迎来撩!!

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: