Heim > Artikel > Web-Frontend > So implementieren Sie den Responsive-Prinzip-Effekt in vue3
export let activeEffect = undefined;// 当前正在执行的effect class ReactiveEffect { active = true; deps = []; // 收集effect中使用到的属性 parent = undefined; constructor(public fn) { } run() { if (!this.active) { // 不是激活状态 return this.fn(); } try { this.parent = activeEffect; // 当前的effect就是他的父亲 activeEffect = this; // 设置成正在激活的是当前effect return this.fn(); } finally { activeEffect = this.parent; // 执行完毕后还原activeEffect this.parent = undefined; } } } export function effect(fn, options?) { const _effect = new ReactiveEffect(fn); // 创建响应式effect _effect.run(); // 让响应式effect默认执行 }
get(target, key, receiver) { if (key === ReactiveFlags.IS_REACTIVE) { return true; } const res = Reflect.get(target, key, receiver); track(target, 'get', key); // 依赖收集 return res; }
const targetMap = new WeakMap(); // 记录依赖关系 export function track(target, type, key) { if (activeEffect) { let depsMap = targetMap.get(target); // {对象:map} if (!depsMap) { targetMap.set(target, (depsMap = new Map())) } let dep = depsMap.get(key); if (!dep) { depsMap.set(key, (dep = new Set())) // {对象:{ 属性 :[ dep, dep ]}} } let shouldTrack = !dep.has(activeEffect) if (shouldTrack) { dep.add(activeEffect); activeEffect.deps.push(dep); // 让effect记住dep,这样后续可以用于清理 } } }
Behalten Sie eine Zuordnungsbeziehung zwischen Attributen und entsprechenden Effekten bei. Nachfolgende Attributänderungen können eine erneute Ausführung der entsprechenden Effektfunktion auslösen.
set(target, key, value, receiver) { // 等会赋值的时候可以重新触发effect执行 let oldValue = target[key] const result = Reflect.set(target, key, value, receiver); if (oldValue !== value) { trigger(target, 'set', key, value, oldValue) } return result; }
export function trigger(target, type, key?, newValue?, oldValue?) { const depsMap = targetMap.get(target); // 获取对应的映射表 if (!depsMap) { return } const effects = depsMap.get(key); effects && effects.forEach(effect => { if (effect !== activeEffect) effect.run(); // 防止循环 }) }
Wir müssen die Altlasten von Nebeneffektfunktionen beim Rendern vermeiden
const state = reactive({ flag: true, name: 'jw', age: 30 }) effect(() => { // 副作用函数 (effect执行渲染了页面) console.log('render') document.body.innerHTML = state.flag ? state.name : state.age }); setTimeout(() => { state.flag = false; setTimeout(() => { console.log('修改name,原则上不更新') state.name = 'zf' }, 1000); }, 1000)
function cleanupEffect(effect) { const { deps } = effect; // 清理effect for (let i = 0; i < deps.length; i++) { deps[i].delete(effect); } effect.deps.length = 0; } class ReactiveEffect { active = true; deps = []; // 收集effect中使用到的属性 parent = undefined; constructor(public fn) { } run() { try { this.parent = activeEffect; // 当前的effect就是他的父亲 activeEffect = this; // 设置成正在激活的是当前effect + cleanupEffect(this); return this.fn(); // 先清理在运行 } } }# 🎜🎜 #Hier ist zu beachten, dass der Reinigungsvorgang (Reinigungseffekt) beim Auslösen ausgeführt wird und die Sammlung erneut durchgeführt wird (Sammeleffekt). Während der Schleife entsteht eine Endlosschleife.
let effect = () => {}; let s = new Set([effect]) s.forEach(item=>{s.delete(effect); s.add(effect)}); // 这样就导致死循环了Effekt stoppen
export class ReactiveEffect { stop(){ if(this.active){ cleanupEffect(this); this.active = false } } } export function effect(fn, options?) { const _effect = new ReactiveEffect(fn); _effect.run(); const runner = _effect.run.bind(_effect); runner.effect = _effect; return runner; // 返回runner }
export function effect(fn, options:any = {}) { const _effect = new ReactiveEffect(fn,options.scheduler); // 创建响应式effect // if(options){ // Object.assign(_effect,options); // 扩展属性 // } _effect.run(); // 让响应式effect默认执行 const runner = _effect.run.bind(_effect); runner.effect = _effect; return runner; // 返回runner } export function trigger(target, type, key?, newValue?, oldValue?) { const depsMap = targetMap.get(target); if (!depsMap) { return } let effects = depsMap.get(key); if (effects) { effects = new Set(effects); for (const effect of effects) { if (effect !== activeEffect) { if(effect.scheduler){ // 如果有调度函数则执行调度函数 effect.scheduler() }else{ effect.run(); } } } } }
Deep-Proxy
get(target, key, receiver) { if (key === ReactiveFlags.IS_REACTIVE) { return true; } // 等会谁来取值就做依赖收集 const res = Reflect.get(target, key, receiver); track(target, 'get', key); if(isObject(res)){ return reactive(res); } return res; }
Das obige ist der detaillierte Inhalt vonSo implementieren Sie den Responsive-Prinzip-Effekt in vue3. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!