• 原理概括

    • Vue3使用Proxy劫持数据的修改和读取
    • 使用ReflectAPI修改和读取数据
    • 在读取属性时,记录是哪个函数读取的,每一个属性对应一个Set对象
    • 在属性被修改时,使用forEach遍历调用这些函数,完成修改渲染
  • 原理参考图

    image-20230627211424486

    image-20230627211732539

  • 实现代码

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>响应式学习</title>
    </head>
    <body>
        <div>F12打开修改user、user2</div>
    
        <div id="app"></div>
        <div id="app2"></div>
        <div id="app3"></div>
    
       <script>
        let activeEffect;
        const effect=(fn)=>{
            const _effect=()=>{
                fn()
            }
            activeEffect=_effect
            _effect()
        }
    
        let targetMap=new WeakMap()
        const track=(target,key)=>{
            let depsMap=targetMap.get(target)
            if( !depsMap ){
                depsMap=new Map()
                targetMap.set(target,depsMap)
            }
            let deps=depsMap.get(key)
            if( !deps ){
                deps=new Set()
                depsMap.set(key,deps)
            }
            deps.add(activeEffect)
        }
    
        const trigger=(target,key)=>{
            let depsMap=targetMap.get(target)
            let deps=depsMap.get(key)
            deps.forEach(effect=>effect())
        }
    
        const reactive=(target)=>new Proxy(target,{
            get(target,key,receiver){
                track(target,key)
                const res= Reflect.get(target,key,receiver)
                if( res!==null && typeof res==="object" ){
                    return reactive(res)
                }
                return res
            },
            set(target,key,value,receiver){
                const res=Reflect.set(target,key,value,receiver)
                trigger(target,key)
                return res
            }
        })
    
        const user=reactive({
            name:'xxcheng',
            age:18,
            sex:'男',
            book:{
                name:'海底两万里'
            }
        })
    
        effect(()=>{
            document.querySelector('#app').innerText=`app:name:${user.name},age:${user.age},sex:${user.sex},book.name:${user.book.name}`;
        })
    
        const user2=reactive({
            name:'jpc',
            age:11,
            sex:'男'
        })
    
        effect(()=>{
            document.querySelector('#app2').innerText=`app2:name:${user2.name},age:${user2.age},sex:${user2.sex}`;
        })
    
        effect(()=>{
            document.querySelector('#app3').innerText=`app3:name:${user2.name},age:${user2.age},sex:${user2.sex}`;
        })
    
       </script>
    </body>
    </html>

    点击打开

  • 运行测试

    • 修改前

      image-20230627212033414

    • user.name修改为www123

      image-20230627212105442

    • user.book.name修改为喜羊羊与灰太狼

      image-20230627212149274

    • user2.age修改为999

      image-20230627212220142

  • 参考链接

文章目录