Vue 双向绑定(2) : 观察者订阅者

36 篇文章 1 订阅
16 篇文章 0 订阅

上一篇 https://blog.csdn.net/qq_38765789/article/details/99952976 讲到数据劫持部分, 这一部分实现一个订阅者

 

1.需要一个可以容纳订阅者的消息订阅器Dep

        function Dep(){
  		this.subs = [];
  	}
  	Dep.prototype = {
  		addSub:function(sub){
  			this.subs.push(sub);
  		},
  		notify:function(){
  			// 依次通知
  			this.subs.forEach(sub=>{
  				sub.update();
  			})
  		}
  	}

2.订阅者

        // vm是vue实例
  	// exp指令的属性值 比如v-model='name'的name
  	// cb是更新函数
 	function Watcher(vm, exp, cb) {
	    this.cb = cb;
	    this.vm = vm;
	    this.exp = exp;
	    this.value = this.get();  // 将自己添加到订阅器的操作
	}
	 
	Watcher.prototype = {
	    update: function() {
	        var value = this.vm.data[this.exp];  //data.name 可能已经更改的数据
	        var oldVal = this.value; // 添加订阅者时初始化的数据
	        // 判断是否需要更新
	        if (value !== oldVal) {
	            this.value = value;
	            this.cb.call(this.vm, value, oldVal);
	        }
	    },
	    get: function() {
	        Dep.target = this;  // 缓存自己
	        var value = this.vm.data[this.exp]  // selfVue.data['name'] 触发Observe中的get 
	        Dep.target = null;  // 释放自己 由于target是Dep的原型变量,以免影响其他观察者
	        return value;
	    }
	};

3. 修改观察者(发布者)部分

        function defineProxy(obj,key,value){
  		// 递归所有子属性
  		Observe(value);

  		// 对于每一个属性,都有一个订阅者数组
  		let dep = new Dep();

  		// 每调用一次defineProxy,就产生一个该函数上下文,保存这个val
  		let val = value;
  		Object.defineProperty(obj,key,{
  			enumerable:true,
	  		configurable:true,
	  		set(newVal){
	  			if(val === newVal){
	  				return;
	  			}
	  			console.log(`${val}=>${newVal}`)
	  			val = newVal;
	  			dep.notify(); //通知订阅者
	  		},
	  		get(){
	  			if(Dep.target){
	  				dep.addSub(Dep.target)
	  			}
	  			return val;
	  		}
  		})
  	}
  	function Observe(data){
  		if (!data || typeof data !== 'object') {
        	return;
	    }
	    Object.keys(data).forEach(function(key) {
	        defineProxy(data, key, data[key]);
	    });
  	}

4.初始化Vue实例

        function SelfVue (data, el, exp) {
	    this.data = data;
	    Observe(data);
	    el.innerHTML = this.data[exp];// 初始化模板数据的值 exp:data.name  

	    // 添加订阅者
	    new Watcher(this, exp, function (value) {
	        el.innerHTML = value;
	    });
	    return this;
	}


    	var ele = document.querySelector('#name');
        var selfVue = new SelfVue({
            name: 'hello world'
        }, ele, 'name');

        function changeName(){
    	    selfVue.data.name =  document.querySelector('#editName').value; //触发data的set拦截器
        }

5.测试

 

这样就实现了一个简单的双向绑定,但还是需要一个模板解析器compile,用来解析所有结点,并将需要绑定数据的结点绑定为订阅者。具体可以参考https://github.com/canfoo/self-vue/tree/master/v2

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值