文档用于自学整理知识点,来自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 接受的参数有两个痛点:
和 .value 类似,为了保持响应性,你始终需要以 props.x 的方式访问这些 prop。这意味着你不能够解构 defineProps 的返回值,因为得到的变量将不是响应式的、也不会更新。
当使用基于类型的 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传递的值