当前位置: 首页 > news >正文

前端基础之《Vue(4)—响应式原理》

一、什么是响应式

1、响应式英文reactive
当你get/set一个变量时,你有办法可以“捕获到”这种行为。

2、一个普通对象和一个响应式对象对比

(1)普通对象

<script>
    // 这种普通对象不具备响应式
    var obj1 = {
        a: 1,
        b: 2
    }
</script>

普通对象,当我们获取、修改属性的时候没办法捕获get/set行为(这种普通对象是不具备响应式的):

(2)响应式对象

<script>
    var obj2 = {}
    var a = 1
    var b = 2
    // 给obj2这个对象添加一个新属性
    Object.defineProperty(obj2, 'a', {
        get() {
            console.log(`有人访问了a`)
            return a
        },
        set(val) {
            console.log(`有人修改了a`)
            a = val
        }
    }) // 给obj2对象加一个a属性
    
    Object.defineProperty(obj2, 'b', {
        get() {
            console.log(`有人访问了b`)
            return b
        },
        set(val) {
            console.log(`有人修改了b`)
            b = val
        }
    }) // 给obj2对象加一个b属性
    
</script>

当获取、修改obj2属性的时候,会触发钩子函数。obj2对象多了get和set函数。obj2具有了响应式:

二、响应式原理

1、流程图

2、代码

<html>
<head>
    <title>响应式原理</title>
    
</head>
<body>
    输入:<input id="ipt" type="text" />
    输出:<h2 id="h2" style='display:inline-block;'></h2>
    <hr>
    <h1 id="h1"></h1>
    <button id="btn">自增</button>

    <script>
        // 这是模拟data选项(普通的对象)
        const data = {
            name: '张三',
            num: 1
        }

        // 这是模拟vue组件实例
        const app = {}

        // 对data进行遍历,['name', 'num']
        // 遍历完了把数组放到app上
        // 生命周期的第一阶段(劫持,就是添加get/set)
        Object.keys(data).forEach(k=>{
            Object.defineProperty(app, k, {
                // handle加劫持
                get() {
                    console.log(`getter ${k}`) // touch操作
                    return data[k]
                },
                set(val) {
                    console.log(`setter ${k}`) // notify操作
                    data[k] = val
                    
                    watcher(k) // 通知更新界面
                }
            })
        })

        // dep对象专门用于依赖收集的
        const dep = {
            name: [],
            num: []
        }

        // 生命周期的第二阶段(相当于挂载阶段)
        // Collect as Dependency依赖收集
        function init() {
            // 模拟v-model='name'
            dep['name'].push(() => { // 依赖收集
                document.getElementById('ipt').value = app.name // get功能
            })
            // 绑定input事件
            document.getElementById('ipt').addEventListener('input', ev => {
                app.name = ev.target.value // set功能
            })

            // 模拟v-text='name'
            dep['name'].push(() => {
                document.getElementById('h2').innerText = app.name // get功能
            })

            dep['num'].push(()=> {
                document.getElementById('h1').innerText = app.num // get功能
            })

            document.getElementById('btn').addEventListener('click', ev => {
                app.num++ //set功能
            })

            // 第一次更新DOM
            Object.keys(dep).forEach(k=>watcher(k))
        }

        // 封装一个Watcher
        function watcher(k) {
            dep[k].forEach(fn=>fn()) // 循环调用变量依赖的function
        }

        // 调用init
        init()
    </script>

</body>
</html>

3、说明
(1)生命周期的第一阶段(劫持,就是添加get/set)
"Touch"和Notify
(2)生命周期的第二阶段(相当于挂载阶段)
把DOM放在真实的DOM上渲染,Collect as Dependency依赖收集
收集的结果是得到一个Watcher,通过re-render更新DOM(以后变量有变化,我通知Watcher,让Watcher再去更新界面)
(3)依赖收集
我要改变表单的值,并且要push一个依赖

二、vue的响应式原理小结

1、正常的对象是没有办法做更新的,必须要给它加钩子,才能知道它被访问

2、解释几个重要概念
劫持:使用Object.defineProperty对data选项进行遍历并添加getter/setter的钩子
touch:当指令第一次与声明式变量绑定时,第一次触发声明式变量的get钩子
依赖收集:当第一次touch时,把当前声明式变量的更新方法添加到dep依赖数组中
watcher:与声明式变量对应的DOM方法
re-render:当声明式变量被set时,Vue通知watcher更新DOM

3、响应式原理
当vue组件被创建时,在生命周期的第一阶段,vue使用Object.defineProperty()对data选项进行遍历劫持并添加get/set钩子。
在生命周期第二阶段,指令第一次与声明式变量touch时,发生依赖收集,再调用当前组件的watch第一次更新DOM,DOM视图就显示出来了。
当声明式变量发生变化时,vue再次通知watcher更新视图,这就是响应式。
 

相关文章:

  • HCIP(网络类型)
  • 文件操作和 IO
  • 数字人文字转语音-TTS--局域网共用一个数字人平台部署 模型存储更改TTS_HOME
  • 【HD-RK3576-PI】Linux制作deb包的方法
  • STM32 HAL库之GPIO示例代码
  • YSlow使用指南
  • FreeRTOS使任务处于阻塞态的API
  • jvm内存如何调优
  • UWB双通道隧道人员定位方案
  • KWDB创作者计划—KWDB:国产分布式多模数据库的创新实践
  • java爬虫案例
  • JAVA SE 自我总结
  • React useEffect
  • 虚幻引擎5-Unreal Engine笔记之“将MyStudent变量设置为一个BP_Student的实例”这句话如何理解?
  • 双数之和+三数之和+四数之和
  • CyclicBarrier 基本用法
  • 【JS进阶】对象解构与数组解构
  • 基于3A4000及CentOS的银河麒麟V10离线源码编译安装VLC
  • Java八股文背诵 第四天JVM
  • BC3 有容乃大(sizeof关键字,sizeof(long long) >= sizeof(long) >= sizeof(int)
  • 昌吉做网站需要多少钱/上海网络推广公司
  • 日本的网页建设网站/seo全称英文怎么说
  • 门户网站和新闻网站的区别/策划营销推广方案
  • 做外贸没网站可以吗/市场推广方案范文
  • 做传奇网站/各大网站排名
  • 关于我们做网站/广州网站关键词推广