Vue 中通过Watch进行动态增加Compute

831 阅读1分钟

Vue的Watch最通的方式我们都知道,直接静态写死

export default{
data(){
	return {
    	b:13,
        c:23,
        obj:{}
    }
}
watch:{
	["a"](val){
		console.log("new value is" + val);
	}
},
computed:{
	a(){
    	return this.b + this.c;
    }
}
}

再动态一些,比如动态增加了某个变量后,我们要watch它,咋整

onClick() {
	this.$set(this.obj , "var1" , 14);//注意用$set
        this.$watch(`obj.var1` , (newVal)=>{ console.log("new val " + newVal)});
}

但是如果这个变量本身是需要get set的呢?

Object.defineProperty(this.obj , "var1" , {
	get(){this._var1},
    set(val){this.__val1=val}
}

这样搞是不行的,因为this.obj.var1变量将不能参与vue的watch ,computed 等过程,因为vue也是通过defineProperty来搞数据绑定的,如果要新增加一个变量,提供一个理论基础的代码

addProperty(){
    let __this = this;
    let test = function() {
      return __this.b + __this.c;
    };
    this.$watch(test, newVal => {
      __this.$set(__this.obj , "test" , newVal)
    });
}

这样,就给__this.obj增加了一个test的变量,并且它的值会和 b , c的和绑在一起 经过上述总结,可以抽离出一个API

    function VueDefineProperty(target, propName, value) {
      let __this = this;
      if (!value) {
        return;
      }
      if (typeof value.get != "function") {
        return;
      }
      __this.$watch(value.get, newVal => {
        __this.$set(target, propName, newVal);
      });
      if (typeof value.set != "function") {
        return;
      }
      // eslint-disable-next-line no-prototype-builtins
      if(target.hasOwnProperty(propName) == false){
          __this.$set(target , propName , null);
      }
      __this.$watch(()=>target[propName], value.set);
    }

需要注意的是

      if(target.hasOwnProperty(propName) == false){
          __this.$set(target , propName , null);
      }

这一行的意义重大,因为watch在最初会进行一次get运算,来确定到底会波及到那些变量。如果最开始没有该变量,那watch就会失效的 使用的方法

    this.VueDefineProperty(this.obj, "abc" , {
      get: () => {
        return this.data1.data11.a2;
      },
      set(val) {
        console.log("value set " + val);
        this.data1.data11.a2 = val;
      }
    });