# 参考

vue2 的响应式

全局 set (opens new window)
深入响应式原理 (opens new window)

vue3 的响应式

组合式 API (opens new window)
响应式基础 (opens new window)
深入响应式系统 (opens new window)

# 一、知识回顾

# 1、代理/劫持

  • 数据代理

数据代理主要用于将组件的数据和属性访问委托给 Vue 实例本身,以便在访问和修改组件数据时可以触发 Vue 的响应式系统;

  • 数据劫持

数据劫持主要用于拦截和处理组件数据的访问和修改操作,以便在数据变化时可以通知 Vue 响应式系统更新视图

# 2、vue2 缺陷

问题描述:

  • 新增属性删除属性, 界面不会更新。
  • 直接通过下标修改数组, 界面不会自动更新。

解决方案:

  • 对象类型:通过Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)。
  • 数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)
快速演示
<template>
  <div>
    对象:{{person}} <br />
    数组:{{hobby}} <br />
    <button @click="addSex">新增属性</button>
    <button @click="deleteAge">删除属性</button>
    <button @click="updateHobby">数组操作</button>
    <br />
  </div>
</template>
<script>
  export default {
    data() {
      return {
        person: {
          name: 'lencamo',
          age: 20
        },
        hobby: ['喝酒', '吉他', '游泳']
      }
    },
    methods: {
      addSex() {
        // 无效(页面不更新)
        // this.person.sex = '男'

        // 解决
        this.$set(this.person, 'sex', '男')
        // Vue.set(this.person, 'sex', '男')
      },
      deleteAge() {
        // 无效(页面不更新)
        // delete this.person.age

        // 解决
        this.$delete(this.person, 'age')
        // Vue.delete(this.person, 'sex', '男')
      },
      updateHobby() {
        // 无效(页面不更新)
        this.hobby[0] = '睡觉'

        // 解决
        this.$set(this.hobby, 0, '睡觉')
        // this.hobby.splice(0,1,'睡觉')
      }
    }
  }
</script>

# 二、响应式原理

# 1、前情回顾

  上一章节,我们已经提到了:

对象(或数组)类型数据, 它内部会自动通过 reactive() 转为代理对象

  那 reactive()可以解决 vue2 中的响应式问题吗?

猜想验证
<div id="app">
  对象:{{person}} <br />
  数组:{{hobby}} <br />
  <button @click="addSex">新增属性</button>
  <button @click="deleteAge">删除属性</button>
  <button @click="updateHobby">数组操作</button>
  <br />
</div>

<script>
  const { createApp, reactive } = Vue

  createApp({
    setup() {
      let person = reactive({
        name: 'lencamo',
        age: 20
      })

      let hobby = reactive(['喝酒', '吉他', '游泳'])

      function addSex() {
        // 有效
        person.sex = '男'
      }
      function deleteAge() {
        // 有效
        delete person.age
      }
      function updateHobby() {
        // 有效
        hobby[0] = '睡觉'
      }

      return {
        person,
        hobby,
        addSex,
        deleteAge,
        updateHobby
      }
    }
  }).mount('#app')
</script>

  关于它是如何解决的,那就得从它的原理说起了

当然,现在我们已经知道了 reactive()是使用了 Proxy 对象

# 2、实现原理

  • 示例
let username = '数据劫持'
let age = 21

let person = {
  username: username,
  age: age
}

// 1、采用Proxy
let p = new Proxy(boj, {
  get(target, key) {
    // return target[key]
    // 2、采用Reflect
    return Reflect.get(target, key)
  },

  set(target, key, value) {
    // target[key] = value
    Reflect.set(target, key, value)
  },

  deleteProperty(target, key) {
    // return delete target[key]
    return Reflect.deleteProperty(target, key)
  }
})
更新于 : 8/7/2024, 2:16:31 PM