《Vue进阶教程》(7)响应式系统介绍

发布于:2025-09-03 ⋅ 阅读:(18) ⋅ 点赞:(0)

本期将介绍VUE.JS响应式原理的核心实现
参考视频教程,点击这里查看

1 什么是响应式

:::info
当数据改变时, 引用数据的函数会自动重新执行

:::

2 手动完成响应过程

首先, 明确一个概念:** 响应式是一个过程**, 这个过程存在两个参与者: 一方触发, 另一方响应

:::warning
比如说, 我们家小胖有时候不乖, 我会打他, 他会哭. 这里我就是触发者, 小胖就是响应者

:::

同样, 所谓数据响应式的两个参与者

  • 触发者: 数据
  • 响应者: 引用数据的函数

当数据改变时, 引用数据的函数**响应**数据的改变, 重新执行

我们先手动完成响应过程

示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app"></div>
    <script>
      // 定义一个全局对象: `触发者`
      const obj = { name: 'hello' }

      // effect函数引用了obj.name, 这个函数就是 `响应者`
      function effect() {
        // 这里可以通过app拿到DOM对象
        app.innerHTML = obj.name
      }

      effect()

      // 当obj.name改变时, 手动执行effect函数, 完成响应过程
      setTimeout(() => {
        obj.name = 'brojie'
        effect()
      }, 1000)
    </script>
  </body>
</html>

为了方便, 我们把引用了数据的函数 叫做 副作用函数

3 副作用函数

:::info
如果一个函数引用了外部的资源, 这个函数会受到外部资源改变的影响

我们就说这个函数存在副作用. 因此, 也把该函数叫做副作用函数

:::

这里, 大家不要被这个陌生的名字吓唬住

所谓副作用函数就是引用了数据的函数或者说数据关联的函数

4 自定义设置过程

如果我们能感知数据改变, 拦截到赋值操作. 自定义设置过程

在赋值的同时调用一下数据关联的副作用函数, 就可以实现**自动**重新执行

理论上可行, 开始动手实践

1) Proxy代理对象

这里我们需要先补充一下Proxy相关的知识. 如果已经知道的小伙伴可以略过

:::info
new Proxy: 传入一个源对象, 返回一个新对象(代理对象)

当访问代理对象的属性时, 可以自定义访问过程

当设置代理对象的属性时, 可以自定义设置过程

:::

示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      // 定义一个源对象(目标对象)
      const obj = { name: 'xiaopang' }
      
      // 创建一个代理对象
      const proxy = new Proxy(obj, {
        get(target, key) {
          // 当访问proxy代理对象的属性时, 会执行get函数
          // 将get函数的返回值作为表达式的值
          console.log(target, key)
          return target[key] // obj.name obj[name]
        },
        set(target, key, value) {
          // 当设置proxy代理对象的属性时, 会执行set函数
          console.log('自定义set操作', value)
          target[key] = value
          return true
        },
      })
      // console.log(proxy.name)
      // console.log(proxy.age)
      proxy.name = 'xxp'
      console.log(obj)
    </script>
  </body>
</html>

这样就确定了思路

  1. 先创建代理对象
  2. 再操作代理对象(给代理对象赋值)

2) 最基本的reactive函数

定义一个函数reactive, 传入一个普通对象, 返回代理对象

示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      function isObject(value) {
        return typeof value === 'object' && value !== null
      }
      /**
       * 创建响应式数据
       *  @param [object]: 普通对象
       *  @return [Proxy]: 代理对象
       */
      function reactive(data) {
        if (!isObject(data)) return

        return new Proxy(data, {
          get(target, key) {
            return target[key]
          },
          set(target, key, value) {
            target[key] = value
            return true
          },
        })
      }

      const state = { name: 'xiaopang' }
      const p = reactive(state)
      p.name = 'xxp'
      console.log(p.name)
    </script>
  </body>
</html>

5 最基本的响应式

既然可以自定义set操作, 只需要在自定义set操作时, 重新执行属性关联的副作用函数

示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app">hello</div>
    <script>
      /**
       * 定义响应式
       *  @param [object] : 普通对象
       *  @return [Proxy] : 代理对象
       */
      function reactive(data) {
        // 如果传入的data不是一个普通对象, 不处理
        if (typeof data !== 'object' || data == null) return

        return new Proxy(data, {
          get(target, key) {
            console.log(`自定义访问${key}`)
            return target[key]
          },
          set(target, key, value) {
            console.log(`自定义设置${key}=${value}`)
            target[key] = value // 先更新值
            effect() // 再调用effect, 调用effect时会重新获取新的数据
            return true
          },
        })
      }

      const pState = reactive({ name: 'hello' })

      function effect() {
        app.innerHTML = pState.name
      }

      setTimeout(() => {
        pState.name = 'brojie'
      }, 1000)
    </script>
  </body>
</html>

**看到这里, 恭喜你, 已经掌握了最核心的原理**🤝

:::danger
💡 小结

  1. 响应式是一个过程, 存在触发者响应者
  2. 数据的改变, 触发关联的副作用函数响应(重新执行)
  3. 通过Proxy代理源数据
  4. 在Proxy的自定义set操作中, 重新执行副作用函数

:::
若有收获,就点个赞吧!
持续更新webgis开发相关技术/面试/就业内容
关注我学习webgis开发不迷路👇👇👇


网站公告

今日签到

点亮在社区的每一天
去签到