Skip to content

3.5 新特性

❗ 没有包含所有更新,只记录后续开发可能会用得到的改进

水合改进

useId

新引入一个 api: useId, 生成每个应用唯一的 ID, 确保在服务端和客户端渲染之间保持稳定:

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>

data-allow-mismatch

在某些情况下,客户端的值和服务端的值会不可避免的不同(如日期),可以使用新 api: data-allow-mismatch 来抑制水合不匹配的警告:

html
<span data-allow-mismatch>{{ data.toLocaleString() }}</span>

响应式解构

vue
<script setup>
const props = withDefaults(
  defineProps<{
    count?: number
    msg?: string
  }>(),
  {
    count: 0,
    msg: 'hello'
  }
)
</script>
vue
<script setup>
const { count = 0, msg = 'hello' } = defineProps<{
  count?: number
  message?: string
}>()
</script>

结构后得变量会自动编译为:props.var

useTemplateRef()

增加了一种新的模板引用方式:useTemplateRef()

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

新模板引用方式主要改进了 v-for 循环中的行为:

  • 传统 ref 在 v-for 中容易出错和内存泄露;
  • useTemplateRef 完美地解决了上述问题。它会自动响应列表的变化,其对应的 ref 值总会指向“当前”最新的、正确的元素:
    • 当列表项被移除时,对应的引用会自动变为 null;
    • 当列表项被添加时,会生成新的引用指向新元素;
    • 你无需手动维护一个引用数组,它本身是响应式的。

示例(ref):

vue
<template>
  <div v-for="item in list" :key="item.id" :ref="setItemRef">
    {{ item.name }}
  </div>
</template>

<script setup>
import { ref, onBeforeUpdate } from 'vue';

const list = ref([...]); // 一些数据
const itemRefs = ref([]); // 用于存放引用的数组

// 设置引用的函数
const setItemRef = (el) => {
  if (el) {
    itemRefs.value.push(el);
  }
};

// 重要:在更新前清空数组,否则会不断累积旧的引用
onBeforeUpdate(() => {
  itemRefs.value = [];
});
</script>

示例(useTemplateRef):

vue
<template>
  <div v-for="item in list" :key="item.id" :ref="itemRefs.set">
    {{ item.name }}
  </div>
</template>

<script setup>
import { useTemplateRef } from 'vue';

const list = ref([...]); // 一些数据

// 创建一个模板引用列表
const itemRefs = useTemplateRef('itemRefsKey'); // 需要提供一个唯一的 key

// 注意:itemRefs 本身是一个 ref,但其值是一个对象(或 null)
// 在 onMounted 后,你可以通过 itemRefs.value 来访问所有当前元素的引用
// 例如:itemRefs.value[0] 指向第一个元素
</script>

Deferred Teleport

使用 teleport 传送时,引入 defer 属性,它会在当前渲染周期之后进行挂载

vue
<template>
  <Teleport defer target="#container">...</Teleport>
  <div id="container"></div>
</template>

onWatcherCleanup()

引入一个新 api: onWatcherCleanup, 用于在 watch 中注册清理回调:

vue
<script setup>
import { watch, onWatcherCleanup } from "vue";

watch(id, (newId) => {
  const controller = new AbortController();

  fetch(`/api/${newId}`, { signal: controller.signal }).then(() => {
    // callback logic
  });

  onWatcherCleanup(() => {
    // abort stale request
    controller.abort();
  });
});
</script>
2025( )
今日 20.83%
本周 42.86%
本月 10.00%
本年 67.40%
Powered by Snowinlu | Copyright © 2024- | MIT License