ES6 Proxy实现Vue的变化检测问题

2020-06-13 10:39:07易采站长站整理

Vue变化检测Object使用DefineProperty、数组使用方法拦截实现。最近,Vue3.0将采用ES6 Proxy的形式重新实现Vue的变化检测,在官方还没给出新方法之前,我们先实现一个基于Proxy的变化检测。

模块划分

参照之前Vue变化检测的代码,将Vue 变化检测的功能分为以下几个部分。

Observer
Dep
Watcher
Utils

首先,我们要确定的问题是,将Dep依赖搜集存在哪里。Vue 2.x里,Object的依赖收集放在defineRactive,Array的依收集存入到Observer中。ES6 Proxy里,考虑到让handler访问dep,我们将依赖放入到Observer中。

Observer

observer.js功能代码如下:


import Dep from './dep';
import { isObject } from './utils';
export default class Observer {
constructor (value) {
// 递归处理子元素
this.obeserve(value);
// 实现当前元素的代理
this.value = this.proxyTarget(value);
}
proxyTarget (targetBefore, keyBefore) {
const dep = new Dep();
targetBefore.__dep__ = dep;
let self = this;
const filtersAtrr = val => ['__dep__', '__parent__'].indexOf(val) > -1;
return new Proxy(targetBefore, {
get: function(target, key, receiver){
if (filtersAtrr(key)) return Reflect.get(target, key, receiver);
if (!Array.isArray(target)) {
dep.depend(key);
}
// sort/reverse等不改变数组长度的,在get里触发
if (Array.isArray(target)) {
if ((key === 'sort' || key === 'reverse') && target.__parent__) {
target.__parent__.__dep__.notify(keyBefore);
}
}
return Reflect.get(target, key, receiver);
},
set: function(target, key, value, receiver){
if (filtersAtrr(key)) return Reflect.set(target, key, value, receiver);
// 新增元素,需要proxy
const { newValue, isChanged } = self.addProxyTarget(value, target, key, self);
// 设置key为新元素
Reflect.set(target, key, newValue, receiver);
// notify
self.depNotify(target, key, keyBefore, dep, isChanged);
return true;
},
});
}
addProxyTarget(value, target, key, self) {
let newValue = value;
let isChanged = false;
if (isObject(value) && !value.__parent__) {
self.obeserve(newValue);
newValue = self.proxyTarget(newValue, key);
newValue.__parent__ = target;
isChanged = true;
}
return {
newValue,
isChanged,
}
}
depNotify(target, key, keyBefore, dep, isChanged) {
if (isChanged && target.__parent__) {
target.__parent__.__dep__.notify(keyBefore);