Vue3响应性语法糖

文档用于自学整理知识点,来自Vue官方文档摘取

在Vue3中响应式语法糖默认处于禁用状态,并且是组合式API特有!!如需使用:所有配置都需要 vue@^3.2.25

Vite
  • 需要 @vitejs/plugin-vue@>=2.0.0

  • 应用于 SFC 和 js(x)/ts(x) 文件。在执行转换之前,会对文件进行快速的使用检查,因此不使用宏的文件应该不会有性能损失。

  • 注意 reactivityTransform 现在是一个插件的顶层选项,而不再是位于 script.refSugar 之中了,因为它不仅仅只对 SFC 起效。

// vite.config.js
export default {
  plugins: [
    vue({
      reactivityTransform: true
    })
  ]
}

ref 和 $ref

ref 需要到处使用 .value 则感觉很繁琐,并且在没有类型系统的帮助时很容易漏掉 .value

语法糖:

<script lang="ts" setup>
import { $ref } from "vue/macros";

let count = $ref(0);
console.log("🚀 ~ file: AboutView.vue:## ~ count", count);

function increment() {
  count++
}

</script>

当启用响应性语法糖时,这些宏函数都是全局可用的、无需手动导入

每一个会返回 ref 的响应式 API 都有一个相对应的、以 $ 为前缀的宏函数。包括以下这些 API:

  • ref -> $ref

  • computed -> $computed

  • shallowRef -> $shallowRef

  • customRef -> $customRef

  • toRef -> $toRef

注意:如果不在"vue/macros"中引入,vsCode插件可能会报错,但是项目运行时,功能还是正常可用的


通过 $() 解构

我们常常会让一个组合函数返回一个含数个 ref 的对象,然后解构得到这些 ref。对于这种场景,响应性语法糖提供了一个 $() 宏:

import { ref } from "vue";
function fn() {
  return {
    name: ref("真白"),
    age: ref(24),
  };
}
const { name, age } = $(fn());
console.log("🚀 ~ file: AboutView.vue:18 ~ name,age", name, age);

const changeInfo = () => {
  name = "天天";
  age = 20;
};

使用$()解构出来的"name","age"也是ref对象

注意!!!编辑器会报错会报错!!让你安装jquery 我真的很无语!!

用 $() 将现存的 ref 转换为响应式对象

在某些场景中我们可能已经有了会返回 ref 的函数。然而,Vue 编译器并不能够提前知道该函数会返回一个 ref。那么此时可以使用 $() 宏来将现存的 ref 转换为响应式变量。

function myCreateRef() {
  return ref(0)
}

let count = $(myCreateRef())

响应式 props 解构

现在的 <script setup> 中对 defineProps 接受的参数有两个痛点:

  1. 和 .value 类似,为了保持响应性,你始终需要以 props.x 的方式访问这些 prop。这意味着你不能够解构 defineProps 的返回值,因为得到的变量将不是响应式的、也不会更新。

  1. 当使用基于类型的 props 的声明时,无法很方便地声明这些 prop 的默认值。为此我们提供了 withDefaults() 这个 API,但使用起来仍然很笨拙。

因此可以通过解构defineProps返回值来解决:

  • 父组件传递参数

<!-- 父组件 -->
<template>
  <Demo :firstName="obj.firstName" :lestName="obj.lestName"></Demo>
</template>
<script lang="ts" setup>
import { reactive } from "vue";
import Demo from "@/components/Demo.vue";

const obj = reactive({
  firstName: "真白",
  lestName: "天天",
});
</script>

  • 子组件接受props并解构

<script lang="ts" setup>
import { watchEffect } from "vue";
interface P {
  firstName: string;
  lestName: string;
}

// 设置默认值  设置别名
const { firstName = "默认值", lestName: name1 } = defineProps<P>();

console.log("🚀 ~ file: Demo.vue:11 ~ lestName", name1);
console.log("🚀 ~ file: Demo.vue:11 ~ firstName", firstName);

watchEffect(() => {
  // 会在 props 变化时打印
  console.log(name1, firstName);
});
</script>

保持在函数间传递时的响应性
以参数形式传入函数

如果使用$ref()创建的响应式对象,以参数形象传入函数中,会造成“响应性丢失”的问题。

例如:(例子取自官方文档)

function trackChange(x: Ref<number>) {
  watch(x, (x) => {
    console.log('x 改变了!')
  })
}

let count = $ref(0)
trackChange(count) // 无效!

传入的其实不并是真正的ref对象,而是 .value之后的结果

要解决这个问题,可以在参数传入之前,用 $$() 包装,包装后代码编译的结果为:

import { ref } from 'vue'

let count = ref(0)
trackChange(count)

会将count转换成真的ref对象

作为函数返回值

如果将响应式变量直接放在返回值表达式中会丢失掉响应性:

function useMouse() {
  let x = $ref(0)
  let y = $ref(0)

  // 监听 mousemove 事件

  // 不起效!
  return {
    x,
    y
  }
}

为了保持响应性,我们需要返回的是真正的 ref,而不是返回时 ref 内的值。

我们还是可以使用 $$() 来解决这个问题。在这个例子中,$$() 可以直接用在要返回的对象上,$$() 调用时任何对响应式变量的引用都会保留为对相应 ref 的引用:

function useMouse() {
  let x = $ref(0)
  let y = $ref(0)

  // 监听 mousemove 事件

  // 修改后起效
  return $$({
    x,
    y
  })
}

在已解构的 props 上使用 $$()

当然在已解构的props属性上面同样适用:

只适用于转换为ref对象,Vue中不允许在子组件中修改通过props传递的值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值