1. 响应式API
vue3中最核心的就是基于
Proxy实现的响应式API(用于代理对象类型)
reactive:vue3中能够将对象变成响应式的API,不管对象有多少层shallowReactive:vue3中能够将对象变成响应式的API,只代理最外层对象readonly:将对象属性变为只读,且不管对象有多少层shallowReadonly:将对象属性变为只读,但是只代理最外层
2. reactivity响应式原理
reactivity文件夹下的src中就是实现响应式逻辑的源码
index.ts:入口文件reactive.ts:响应式APIbaseHandler.ts:getter、setter的处理逻辑operators.ts:定义公共标识effect.ts:依赖收集,副作用函数(依赖)effect、属性收集依赖track、通知依赖执行triggerref.ts:ref、toRef实现computed.ts:计算属性
3. 实现响应式API
3.1 shared模块
shared模块是vue3中用于存储共享方法的包模块,相当于utils,shared中的方法都在src下index.ts中
// 这里我们先实现一些常用的
export const isObject = val => typeof val === 'object' && val !== null;
export const extend = Object.assign;
export const isArray = Array.isArray;
export const isFunction = val => typeof val === 'function';
export const isNumber = val => typeof val === 'number';
export const isString = val => typeof val === 'string';
export const isIntegerKey = key => parseInt(key) + '' === key;
let hasOwnProperty = Object.prototype.hasOwnProperty;
export const hasOwn = (target,key) => hasOwnProperty.call(target,key);
export const hasChanged = (oldValue,value) => oldValue !== value;
3.2 reactive.ts
入口文件
reactvity/src/index.ts
// reactvity/src/index.ts
export {
reactive,
readonly,
shallowReactive,
shallowReadonly
} from './reactive'
响应式API
import {isObject} from '@vue/shared/src'
import {
mutableHandlers,
readonlyHandlers,
shallowReactiveHandlers,
shallowReadonlyHandlers
} from "./baseHandlers"; // 不同的拦截函数
// 是不是仅读,是不是深度,基于柯里化编程实现
export function reactive(target) {
return createReactiveObject(target, false, mutableHandlers)
}
export function shallowReactive(target) {
return createReactiveObject(target, false, shallowReactiveHandlers)
}
export function readonly(target) {
return createReactiveObject(target, true, readonlyHandlers)
}
export function shallowReadonly(target) {
return createReactiveObject(target, true, shallowReadonlyHandlers)
}
// createReactiveObject 创建响应式对象
function createReactiveObject(target, isReadonly, baseHandlers) {}
createReactiveObject函数的实现
/**
* createReactiveObject 创建响应式对象
* @param target 拦截的目标
* @param isReadonly 是不是仅读属性
* @param baseHandlers 对应的拦截函数
*/
const reactiveMap = new WeakMap(); // 会自动垃圾回收,不会造成内存泄露,存储的key只能是对象
const readonlyMap = new WeakMap();
export function createReactiveObject(target,isReadonly,baseHandler){
// 如果目标不是对象,没法拦截,reactive 这个 API 只能拦截对象类型
if(!isObject(target)){
return target;
}
// 如果某个对象已经被代理过了,就不要再代理了,也可能一个对象被代理是深度的,又被仅读代理了
const proxyMap = isReadonly ? readonlyMap : reactiveMap;
const existProxy = proxyMap.get(target);
if(existProxy){
return existProxy; // 如果已经被代理了,直接返回即可
}
// 如果没有被代理,则基于 Proxy 实现对象代理
const proxy = new Proxy(target,baseHandler);
proxyMap.set(target,proxy); // 将要代理的对象,和对应代理结果缓存起来
return proxy;
}
3.3 baseHandler.ts
baseHandler.ts中主要实现了拦截器的逻辑(getter、setter)
import { isObject } from "@vue/shared";
import { reactive, readonly } from "./reactive";
const get = createGetter();
const shallowGet = createGetter(false, true);
const readonlyGet = createGetter(true);
const shallowReadonlyGet = createGetter(true, true)
const set = createSetter();
const shallowSet = createSetter(true);
/** createGetter 拦截获取功能
* @param isReadonly 是不是仅读
* @param shallow 是不是浅响应
*/
function createGetter(isReadonly = false, shallow = false) {
return function get(target, key, receiver) {
// 后续Object上的方法会被迁移到 Reflect上
// 以前target[key] = value 方式设置值可能会失败,不会报异常,也没有返回标识
// Reflect 方法是具备返回值的
const res = Reflect.get(target, key, receiver); // target[key]
if (!isReadonly) { // 如果是仅读的无需收集依赖,等数据变化后更新对应视图
console.log('依赖收集')
}
if (shallow) { // 浅无需返回代理
return res
}
if (isObject(res)) { // 取值时递归代理 vue2 是直接递归,vue3是取值时才代理,所以vue3的代理模式是懒代理
return isReadonly ? readonly(res) : reactive(res)
}
return res;
}
}
function createSetter(shallow = false) { // 拦截设置功能
return function set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
return result;
}
}
export const mutableHandlers = {
get,
set
};
export const readonlyHandlers = {
get: readonlyGet,
set(target, key) {
console.warn(`Set operation on key "${String(key)}" failed: target is readonly.`)
return true;
}
};
export const shallowReactiveHandlers = {
get: shallowGet,
set: shallowSet
};
export const shallowReadonlyHandlers = {
get: shallowReadonlyGet,
set(target, key) {
console.warn(`Set operation on key "${String(key)}" failed: target is readonly.`)
return true;
}
};
以上就基本实现了
vue3响应式原理