Skip to content

vue3.5 更新了哪些新功能

响应式 Props 解构

Vue 的响应系统基于属性访问跟踪状态的使用情况。例如,在计算属性或侦听器中访问props.foo时,foo属性将被跟踪为依赖项。

因此,在以下代码的情况下:

js
const { foo } = defineProps(['foo']);

watchEffect(() => {
  // 在 3.5 之前只运行一次
  // 在 3.5+ 中在 "foo" prop 变化时重新执行
  console.log(foo);
});

在 3.4 及以下版本,foo是一个实际的常量,永远不会改变。在 3.5 及以上版本,当在同一个<script setup>代码块中访问由defineProps解构的变量时,Vue 编译器会自动在前面添加props.。因此,上面的代码等同于以下代码:

js
const props = defineProps(['foo'])

watchEffect(() => {
  // `foo` 由编译器转换为 `props.foo`
  console.log(props.foo)
})

此外,你可以使用 JavaScript 原生的默认值语法声明 props 默认值。这在使用基于类型的 props 声明时特别有用。

ts
const { foo = 'hello' } = defineProps<{ foo?: string }>();

将解构的 props 传递到函数中

当我们将解构的 prop 传递到函数中时,例如:

js
const { foo } = defineProps(['foo']);

watch(foo, /* ... */);

这并不会按预期工作,因为它等价于watch(props.foo, ...)——我们给watch传递的是一个值而不是响应式数据源。实际上,Vue 的编译器会捕捉这种情况并发出警告。

与使用watch(() => props.foo, ...)来侦听普通 prop 类似,我们也可以通过将其包装在 getter 中来侦听解构的 prop:

js
watch(() => foo, /* ... */);

useId()

用于为无障碍属性或表单元素生成每个应用内唯一的 ID。

  • 类型
ts
function useId(): string
  • 示例
vue
<script setup>
import { useId } from 'vue';

const id = useId();
</script>

<template>
  <form>
    <label :for="id">Name:</label>
    <input :id="id" type="text" />
  </form>
</template>
  • 详细信息

useId()生成的每个 ID 在每个应用内都是唯一的。它可以用于为表单元素和无障碍属性生成 ID。在同一个组件中多次调用会生成不同的 ID;同一个组件的多个实例调用useId()也会生成不同的 ID。

useId()生成的 ID 在服务器端和客户端渲染之间是稳定的,因此可以安全地在 SSR 应用中使用,不会导致激活不匹配。

如果同一页面上有多个 Vue 应用实例,可以通过app.config.idPrefix为每个应用提供一个 ID 前缀,以避免 ID 冲突。

useTemplateRef()

返回一个浅层 ref,其值将与模板中的具有匹配 ref attribute 的元素或组件同步。

  • 类型
ts
function useTemplateRef<T>(key: string): Readonly<ShallowRef<T | null>>
  • 示例
vue
<script setup>
import { useTemplateRef, onMounted } from 'vue';

const inputRef = useTemplateRef('input');

onMounted(() => {
  inputRef.value.focus();
})
</script>

<template>
  <input ref="input" />
</template>

onWatcherCleanup()

注册一个清理函数,在当前侦听器即将重新运行时执行。只能在watchEffect作用函数或watch回调函数的同步执行期间调用 (即不能在异步函数的await语句之后调用)。

  • 类型
ts
function onWatcherCleanup(
  cleanupFn: () => void,
  failSilently?: boolean
): void
  • 示例
ts
import { watch, onWatcherCleanup } from 'vue';

watch(id, (newId) => {
  const { response, cancel } = doAsyncWork(newId);
  // 如果 `id` 变化,则调用 `cancel`,
  // 如果之前的请求未完成,则取消该请求
  onWatcherCleanup(cancel);
})

其实与watchcallback函数的第三个参数onCleanup的功能一致

js
watch(id, async (newId, oldId, onCleanup) => {
  const { response, cancel } = doAsyncWork(newId);
  // 当 `id` 变化时,`cancel` 将被调用,
  // 取消之前的未完成的请求
  onCleanup(cancel);
  data.value = await response;
})