0
点赞
收藏
分享

微信扫一扫

手动实现vue中的watch监听

梦想家们 2021-09-23 阅读 77

getter和setter

getter 是一种获得属性值的方法,setter是一种设置属性值的方法。
属性被赋值 a = 1的时候, a 的原型内的setter就会被触发;
而 console.log(a) 的时候,a 的原型内的getter就会被触发。

这里选用了比较好构造的一种 Object.defineProperty

如下面一个实例,定义一个新的属性

(function () {
var o = { a : 1}//声明一个对象,包含一个 a 属性,值为1
Object.defineProperty(o,"b",{
get: function () {
return this.a;
},
set : function (val) {
this.a = val;
},
configurable : true
});
console.log(o.b);//==> 1
o.b = 2;
console.log(o.b);//==> 2
})();

configurable是指 "b" 是否可以被再配置,默认是false。
false的话Object.defineProperty(o,"a",{set : function(val){}} );
再修改时会不起作用或者报错,一般默认false。

创建Watch对象

目标实现,以下是我们想要的达到的效果

import watcher from './watcher.js';
let wm = new watcher({
data:{
a: 0
},
watch:{
a(newVal,oldVal){
console.log('newVal:'+newVal);
console.log('oldVal:'+oldVal);
}
}
})
vm.a = 1
// newVal:1
// oldVal:0

创建构造对象

class watcher{
constructor(opts){
this.$data = opts.data;
for(let key in opts.data){
this.setData(key,opts.data[key])
}
}

setData(_key,_val){
Object.defineProperty(this,_key,{
get: function () {
return this.$data[_key];
},
set : function (val) {
const oldVal = this.$data[_key];
if(oldVal === val)return val;
this.$data[_key] = val;
return val;
},
});
}
}

export default watcher;

该对象只是实现了简单的setter和getter,并没有实现对应的监听函数

添加watch事件触发

class watcher{
constructor(opts){
this.$data = this.getBaseType(opts.data) === 'Object' ? opts.data : {};
this.$watch = this.getBaseType(opts.watch) === 'Object' ? opts.watch : {};
for(let key in opts.data){
this.setData(key)
}
}

getBaseType(target) {
const typeStr = Object.prototype.toString.apply(target);

return typeStr.slice(8, -1);
}

setData(_key){
Object.defineProperty(this,_key,{
get: function () {
return this.$data[_key];
},
set : function (val) {
const oldVal = this.$data[_key];
if(oldVal === val)return val;
this.$data[_key] = val;
this.$watch[_key] && typeof this.$watch[_key] === 'function' && (
this.$watch[_key].call(this,val,oldVal)
);
return val;
},
});
}
}

export default watcher;

为了函数内部的健壮性,getBaseType是用来做类型校验的。
Object.defineProperty(this),this把上下文指向当前对象。
this.$watch[_key].call(this,val,oldVal),把监听事件的上下文页绑定到当前对象,方便在watch内通过this获取对象内的值,如下

let wm = new watcher({
data:{
a: 0,
b: 'hello'
},
watch:{
a(newVal,oldVal){
console.log(this.b);
}
}
})

有人可能会问为什么不直接用vue呢。你也知道vue是一个工程级别的框架,做比较大的项目当然是用vue,react;但是单单做一个展示性的官网或者做个移动端的H5宣传页也用上vue吗?那当然是没有必要的。
用上这一个watcher类,可以让你页面的状态控制有条理、有迹可循。

举报

相关推荐

0 条评论