随着Vue3的全面普及,new Proxy成为了无法绕过的话题,更先进的new Proxy为整个Vue3的响应系统提供了动力。
在日常项目开发过程中,我们通常会去”监听“一些值的变化,并通过数据的变化去做某些判断,某些更改等。
selectValueChange () {
// TODO: 根据最新的值,或者变化的这个动作做一些事情
},
watch: {
selectValue (newVal, oldVal) {
// TODO: 根据最新的值、旧值或者变化的这个动作做一些事情
console.log(newVal, oldVal)
},
},
第一种方式:事件绑定的方式,我们虽然能获取到最新的值,以及变化的这个动作,但是我们并不能获取到改变之前的值。此种方式更适用于监听某一个表单项的变化,然后去做一些事情。
第二种方式:通过watch监听,可以获取到newVal和oldVal,但是如果被监听的数据是一个对象,我们并不能直接获取到是对象中具体的哪个属性发生了变化。此种方式更适用于监听某个对象的变化,且可以利用旧值,然后去做一些事情。
某些情况下,我们可能需要监听整个表单中所有表单项的变化,并根据不同的表单项变化做不同的事儿,这个表单可能由几项组成,也可能由几十项、几百项组成。此时如果采用事件绑定的方式无疑代码会异常冗余,难以维护。如果采用watch去监听整个对象,又无法获取到每次变化的具体key是什么。此时就需要Proxy来协助我们了。
一个 Proxy 对象由两个部分组成: target 、 handler 。在通过 Proxy 构造函数生成实例对象时,需要提供这两个参数。 target 即目标对象, handler 是一个对象,声明了代理 target 的指定行为。
handler的属性:
get(target, propKey, receiver):用于 target 对象上 propKey 的读取操作。
set(target, propKey, value, receiver):用于拦截 target 对象上的 propKey 的赋值操作。如果目标对象自身的某个属性,不可写且不可配置,那么set方法将不起作用。
apply(target, ctx, args):用于拦截函数的调用、call 和 reply 操作。target 表示目标对象,ctx 表示目标对象上下文,args 表示目标对象的参数数组。
has(target, propKey):用于拦截 HasProperty 操作,即在判断 target 对象是否存在 propKey 属性时,会被这个方法拦截。此方法不判断一个属性是对象自身的属性,还是继承的属性
construct(target, args):用于拦截 new 命令。返回值必须为对象。
deleteProperty(target, propKey):用于拦截 delete 操作,如果这个方法抛出错误或者返回 false ,propKey 属性就无法被 delete 命令删除。
getOwnPropertyDescriptor(target, propKey):用于拦截 Object.getOwnPropertyD() 返回值为属性描述对象或者 undefined 。
getPrototypeOf(target):主要用于拦截获取对象原型的操作。返回值必须是对象或者 null ,否则报错。另外,如果目标对象不可扩展(non-extensible),getPrototypeOf 方法必须返回目标对象的原型对象。
isExtensible(target):用于拦截 Object.isExtensible 操作。该方法只能返回布尔值,否则返回值会被自动转为布尔值。它的返回值必须与目标对象的isExtensible属性保持一致,否则会抛出错误。
ownKeys(target):用于拦截对象自身属性的读取操作,方法返回的数组成员,只能是字符串或 Symbol 值,否则会报错。若目标对象中含有不可配置的属性,则必须将这些属性在结果中返回,否则就会报错。若目标对象不可扩展,则必须全部返回且只能返回目标对象包含的所有属性,不能包含不存在的属性,否则也会报错。
preventExtensions(target):拦截 Object.preventExtensions 操作,该方法必须返回一个布尔值,否则会自动转为布尔值。
setPrototypeOf:主要用来拦截 Object.setPrototypeOf 方法。返回值必须为布尔值,否则会被自动转为布尔值。若目标对象不可扩展,setPrototypeOf 方法不得改变目标对象的原型。
Proxy.revocable():用于返回一个可取消的 Proxy 实例。
目前开发的项目中有一个复杂的审批意见表单组件,其中包含多种联动赋值及联动显示隐藏的规则,并且在业务层也会根据表单的变化做一些定制化的操作,并且某些定制化内容需要用到变化之前的值即oldVal。因此我需要将变化的表单项的key、oldVal、newVal通知给业务层,并且组件内部也根据这些值做一些判断。
3.1.2 ES6 Reflect 与 Proxy | 菜鸟教程