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>

 

posted @ 2020-10-19 19:06  广广-t  阅读(142)  评论(0)    收藏  举报