Vue3知识点整理(2)- 常用Composition API(1)和 Vue3.0中的响应式原理

目录

一、常用Composition API(1)

1.1 Setup

1.1.1 案例练习

1.2 ref函数

1.2.1 作用

1.2.2 语法

1.2.3 备注

1.2.4 简单案例练习

1.3 reactive函数

1.3.1 作用

1.3.2 语法

1.3.3 简单案例练习

1.4 reactive 对比 ref

1.4.1 定义数据角度对比

1.4.2 原理角度对比

1.4.3 使用角度对比

二、Vue3.0中的响应式原理

2.1 vue2.x的响应式

2.1.1 实现原理

2.1.2 存在问题

2.2 Vue3.0的响应式

2.2.1 实现原理

2.3 案例练习

2.3.1 模拟Vue2中实现响应式

2.3.2 模拟Vue3中实现响应式


一、常用Composition API(1)

Vue3官方文档 - 组合API

1.1 Setup

Vue3官方文档 - Setup

(1)理解:Vue3.0中的一个新的配置项,值为一个函数

(2)组件中所用到的:数据、方法等等,均要配置在setup中

(3)setup函数的两种返回值:

  1. 若返回一个对象,则对象中的属性、方法,在模板中均可以直接使用(重点)
  2. 若返回一个渲染函数:则可以自定义渲染内容(了解即可)

(4)使用setup时需注意:

  1. 尽量不要与Vue2.x配置混用
    1. Vue2.x配置(data、methods、computed...)中可以访问到setup中的属性、方法
    2. 但在setup中不能访问到Vue2.x配置(data、methods、computed...)
    3. 如果有重名,setup优先
  2. setup不能是一个asyn函数,因为返回值不再是return的对象,而是promise,模板获取不到return对象中的属性(后期也可以返回一个Promise实例,但需要Suspense和异步组件的配合 )

(5)setup注意点:

  • setup执行的时机
    • 在beforeCreate之前执行依次,this 是 undefined
  • setup的参数
    • props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性
    • context:上下文对象
      • attrs:值为对象,半酣:组件外部传递过来,但没有在props配置中声明的属性,相当于 this.$attrs
      • slot:收到的插槽内容,相当于 this.$slot
      • emit:分发自定义事件的函数,相当于 this.$emit

1.1.1 案例练习

在App.vue中简单使用setup配置项

<template>
  <h1>游戏信息</h1>
  <h2>游戏名:{{ gname }}</h2>
  <h2>发售日期:{{ date }}</h2>
  <button @click="overDate">获取信息</button>
</template>

<script>
// import h from "vue";
export default {
  name: "App",
  setup() {
    let gname = "Splatoon3";
    let date = "2022年9月9日";
    function overDate() {
      alert(`我个人觉得${gname}是跳票到${date}`);
    }

    // 返回一个对象(常用)
    return {
      gname,
      date,
      overDate,
    };

    // 返回一个函数(渲染函数)
    // return ()=> h('h1','Splatoon3')
  },
};
</script>

1.2 ref函数

Vue3官方文档 - Ref

1.2.1 作用

定义一个响应式的数据

1.2.2 语法

// let xxx = ref(initValue)
const xxx = ref(initValue)
  • 创建一个包含响应式数据的引用对象(reference对象,简称ref对象)
  • JS中操作数据:xxx.value
  • 模板中读取数据:不需要.value,直接{{xxx}}

1.2.3 备注

  • 接收数据可以是:基本类型、也可以是对象类型
  • 基本类型的数据:响应式依然是依靠 object.defineProperty() 中的 getset 完成的
  • 对象类型的数据:内部使用了 Vue3.0 中的一个新函数 —— reactive函数

1.2.4 简单案例练习

在App.vue中简单使用ref对象

<template>
  <h1>游戏信息</h1>
  <h2>游戏名:{{ gname }}</h2>
  <h2>发售日期:{{ date }}</h2>
  <h2>游戏类型:{{ types.gType }}</h2>
  <h2>游戏品类:{{ types.webType }}</h2>
  <button @click="update">修改信息</button>
</template>

<script>
// 引入ref函数
import { ref } from "vue";

export default {
  name: "App",
  setup() {
    // 基本类型的数据
    let gname = ref("Splatoon3");
    let date = ref("2022.9.9");

    // 对象类型的数据
    const types = ref({
      gType: "FPS",
      webType: "Online",
    });

    function update() {
      gname.value = "异度之刃3";
      date.value = "2022.7.29";
      types.value.gType = "JRPG";
      types.value.webType = "Single Game";
    }

    // 返回一个对象(常用)
    return {
      gname,
      date,
      types,
      update,
    };
  },
};
</script>

1.3 reactive函数

Vue3官方文档 - reactive

1.3.1 作用

定义一个对象类型的响应式数据(基本类型用ref函数)

1.3.2 语法

const 代理对象 = reactive(源对象)

接收一个对象(或数组)返回一个代理对象(Proxy实例对象,简称proxy对象)

  • reactive定义的响应式数据是"深层次的"
  • 内部基于ES6的 Proxy 实现,通过 代理对象 操作 源对象内部数据进行操作

1.3.3 简单案例练习

在App.vue中简单使用reactive函数

<template>
  <h1>游戏信息</h1>
  <h2>游戏名:{{ game.gname }}</h2>
  <h2>发售日期:{{ game.date }}</h2>
  <h2>游戏类型:{{ game.types.gType }}</h2>
  <h2>游戏品类:{{ game.types.webType }}</h2>
  <h2>中文名:{{ game.cName }}</h2>
  <button @click="update">修改信息</button>
</template>

<script>
import { reactive } from "vue";
export default {
  name: "App",
  setup() {
    // 数据
    let game = reactive({
      gname: "Splatoon3",
      date: "2022.9.9",
      types: {
        gType: "FPS",
        webType: "Online",
      },
      cName: ["斯普拉遁3", "喷射战士3"],
    });

    // 方法
    function update() {
      game.gname = "Xenoblade3";
      game.date = "2022.7.29";
      game.types.gType = "JRPG";
      game.types.webType = "Single Game";
      game.cName[0] = "异度神剑3";
      game.cName[1] = "异度之刃3";
    }

    // 返回一个对象(常用)
    return {
      game,
      update,
    };
  },
};
</script>

1.4 reactive 对比 ref

1.4.1 定义数据角度对比

  • ref用来定义:基本类型数据
  • reactive用来定义:对象(或数组)类型对象
  • 备注:ref也可以用来定义对象(或数组)类型对象,它内部会自动通过reactive转为代理对象

1.4.2 原理角度对比

  • ref通过 Object.defineProperty()getset 来实现响应式(数据劫持)
  • reactive 通过使用 Proxy 来实现响应式(数据劫持),并通过 Reflect 操作源对象内部的数据

1.4.3 使用角度对比

  • ref定义的数据:操作数据需要 .value,读取数据时模板中直接读取不需要 .value
  • reactive定义的数据:操作数据与读取数据:均不需要 .value

二、Vue3.0中的响应式原理

2.1 vue2.x的响应式

2.1.1 实现原理

  • 对象类型:通过 Object.defineProperty() 对属性的读取、修改进行拦截(数据劫持)
  • 数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)
Object.defineProperty( 对象 , '属性名',{
    get(){},
    set(){}
})

2.1.2 存在问题

  • 新增属性、删除属性,界面不会刷新
  • 直接下标修改数组,界面不会自动属性

问题解决:

  1. Vue.set(target, propertyName/index, value)
  2. vm.$set(target, propertyName/index, value)

Vue官方文档 - Vue.set

Vue官方文档 - vm.$set

案例参考:Vue知识点整理(一)- Vue核心(4)- 数据监测

2.2 Vue3.0的响应式

2.2.1 实现原理

  • 通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
  • 通过Reflect(反射): 对源对象的属性进行操作

MDN文档中描述的Proxy与Reflect:

new Proxy(data, {
	// 拦截读取属性值
    get (target, prop) {
    	return Reflect.get(target, prop)
    },
    // 拦截设置属性值或添加新属性
    set (target, prop, value) {
    	return Reflect.set(target, prop, value)
    },
    // 拦截删除属性
    deleteProperty (target, prop) {
    	return Reflect.deleteProperty(target, prop)
    }
})

2.3 案例练习

2.3.1 模拟Vue2中实现响应式

<!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>
      // 源数据
      let person = {
        name: "周星星",
        age: 20,
      };

      // 模拟Vue2中实现响应式
      let p = {};
      Object.defineProperty(p, "name", {
        configurable: true,
        // 读取name时调用
        get() {
          return person.name;
        },
        // 修改name时调用
        set(value) {
          console.log("Vue2 - 修改了name属性,更新界面");
          person.name = value;
        },
      });
      Object.defineProperty(p, "age", {
        configurable: true,
        // 读取age时调用
        get() {
          return person.age;
        },
        // 修改age时调用
        set(value) {
          console.log("Vue2 - 修改了age属性,更新界面");
          person.age = value;
        },
      });
    </script>
  </body>
</html>

2.3.2 模拟Vue3中实现响应式

<!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>
      // 源数据
      let person = {
        name: "周星星",
        age: 20,
      };

      // // 模拟Vue3中实现响应式
      const p = new Proxy(person, {
        // 读取p的某个属性时调用
        get(target, propName) {
          console.log(`Vue3 - 读取p身上的${propName}属性`);
          return Reflect.get(target, propName);
        },
        // 修改p的某个属性 或 给p追加某个属性
        set(target, propName, value) {
          console.log(`Vue3 - 修改p身上的${propName}属性,更新界面`);
          Reflect.set(target, propName, value);
        },
        // 删除p的某个属性时调用
        deleteProperty(target, propName) {
          console.log(`Vue3 - 删除p身上的${propName}属性,更新界面`);
          return Reflect.deleteProperty(target, propName);
        },
      });
    </script>
  </body>
</html>

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JHY97

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值