Vue3.0响应式原理
Vue3.0的响应式基于Proxy实现。具体代码如下:
1 let targetMap = new WeakMap() 2 let effectStack = [] //存储副作用 3 4 const track = (target, key) => { 5 let effect = effectStack[effectStack.length -1] 6 if(effect){ 7 //收集依赖 8 let depMap = targetMap.get(target) 9 if(depMap === undefined){ 10 depMap = new Map() 11 targetMap.set(target,depMap) //effect dep 集合 12 } 13 14 let dep = depMap.get(key) 15 if(dep === undefined){ 16 dep = new Set() //存储effect 17 depMap.set(key,dep) 18 } 19 20 if(!dep.has(effect)){ 21 dep.add(effect) 22 effect.deps.push(dep) 23 } 24 } 25 } 26 27 const trigger = (target,key) => { 28 let depMap = targetMap.get(target) 29 if(depMap === undefined){ 30 return //没有副作用 31 } 32 33 const effects = new Set() 34 const computeds = new Set() 35 36 if(key){ 37 let deps = depMap.get(key) 38 deps.forEach(effect => { 39 if(effect.computed){ 40 computeds.add(effect) 41 } else { 42 effects.add(effect) 43 } 44 }) 45 } 46 47 effects.forEach(effect => effect()) 48 computeds.forEach(computed => computed) 49 } 50 51 const handler = { 52 get(target,key,receiver){ 53 track(target,key) //依赖收集 54 let ret = Reflect.get(...arguments) 55 return typeof ret == 'object' ? reactive(ret) : ret 56 }, 57 set(target,key,value,receiver){ 58 let info = Reflect.set(...arguments) 59 trigger(target,key) //执行副作用 60 } 61 } 62 63 const reactive = (target) => { 64 let observe = new Proxy(target,handler) 65 return observe 66 } 67 68 const effect = (fn, options={}) => { 69 let e = crateRectiveEffect(fn,options) 70 if(!options.lazy){ 71 e() 72 } 73 return e 74 } 75 76 const crateRectiveEffect = (fn, options) => { 77 const effect = (...args) => { 78 return run(effect, fn, args) 79 } 80 effect.deps = [] 81 effect.computed = options.computed 82 effect.lazy = options.lazy 83 return effect 84 } 85 86 //收集副作用 执行函数 87 const run = (effect, fn, args) => { 88 console.log(fn); 89 if(!effectStack.includes(effect)){ 90 try{ 91 effectStack.push(effect) 92 return fn(...args) 93 } finally { 94 effectStack.pop() 95 } 96 } 97 } 98 99 const computed = (fn) => { 100 const runner = effect(fn,{computed:true,lazy:true}) 101 return { 102 // effect: runner, 103 get value() { 104 return runner() 105 } 106 } 107 }
调用:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>响应式</title> <script src="main.js" type="text/javascript" charset="utf-8"></script> </head> <body> <div id="app"></div> <button id="btn">click </button> <script type="text/javascript"> const root = document.getElementById('app') const btn = document.getElementById('btn') const o = { name:'terry', age:1 } let objj = reactive(o) let double = computed(()=> objj.age*2) effect(()=>{ root.innerHTML = ` <h1>${objj.name}今年${objj.age}岁了, ${double.value}</h1> ` }) btn.addEventListener('click',()=>{ objj.age+=1 },false) </script> </body> </html>
浙公网安备 33010602011771号