宣布 Vue 3.5 发布

原文信息: 查看原文查看原文

Announcing Vue 3.5

- Evan You

今天我们激动地宣布 Vue 3.5 “天元突破 红莲螺岩” 版本的发布!

这个次要版本不包含破坏性变更,并包括了内部改进和有用的新特性。我们将在这篇博文中介绍一些亮点 - 有关完整变更和新特性的列表,请查阅 GitHub 上的完整更新日志

响应系统优化

在 3.5 版本中,Vue 的响应系统经历了另一次重大重构,实现了更好的性能和显著改善的内存使用(减少 56%),且没有行为变化。这次重构还解决了由持久计算值和服务器端渲染(SSR)期间的悬挂计算值引起的陈旧计算值和内存问题。

此外,3.5 还优化了大型、深度响应数组的响应跟踪,使得这类操作在某些情况下速度提高了多达 10 倍。

详情:PR#10397, PR#9511

响应式属性解构

响应式属性解构 功能在 3.5 中已稳定。现在默认启用此功能,从 <script setup> 中的 defineProps 调用中解构出来的变量现在具有响应性。值得注意的是,此功能通过利用 JavaScript 原生默认值语法,显著简化了带有默认值的属性声明:

之前

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

之后

const { count = 0, msg = 'hello' } = defineProps<{
  count?: number
  message?: string
}>()

对解构变量的访问,例如 count,会自动编译为 props.count,因此它们会在访问时被跟踪。类似于 props.count,观察解构属性变量或将其传递给可组合函数时保留响应性,需要将其包装在 getter 中:

watch(count /* ... */)
//    ^ 编译时错误
watch(() => count /* ... */)
//    ^ 包装在 getter 中,按预期工作
// 可组合函数应使用 `toValue()` 规范化输入
useDynamicCount(() => count)

对于那些更喜欢明确区分解构属性和普通变量的人,@vue/language-tools 2.1 已推出了一个可选设置,以启用它们的内联提示:

解构属性的内联提示

详情:

  • 查看 文档 了解用法和注意事项。
  • 查看 RFC#502 了解这项功能的历史和设计理由。

服务器端渲染改进

3.5 带来了一些长期请求的服务器端渲染(SSR)改进。

延迟水合

现在,异步组件可以通过指定 defineAsyncComponent() API 的 hydrate 选项中的策略来控制它们应该何时被水合。例如,只在组件变得可见时才水合:

import { defineAsyncComponent, hydrateOnVisible } from 'vue'
const AsyncComp = defineAsyncComponent({
  loader: () => import('./Comp.vue'),
  hydrate: hydrateOnVisible()
})

核心 API 故意保持较低级别,Nuxt 团队已经在其上构建更高级别的语法糖。

详情:PR#11458

useId()

useId() 是一个 API,可以用来生成每个应用程序唯一的 ID,这些 ID 保证在服务器和客户端渲染之间稳定。它们可以用来生成表单元素和可访问性属性的 ID,并且可以在 SSR 应用程序中使用,而不会导致水合不匹配:

<script setup>
import { useId } from 'vue'
const id = useId()
</script>
<template>
  <form>
    <label :for="id">姓名:</label>
    <input :id="id" type="text" />
  </form>
</template>

详情:PR#11404

data-allow-mismatch

在客户端值不可避免地与服务器端值不同的情况下(例如日期),我们现在可以使用 data-allow-mismatch 属性来抑制由此产生的水合不匹配警告:

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

您还可以通过为属性提供值来限制允许的不匹配类型,可能的值包括 textchildrenclassstyleattribute

自定义元素改进

3.5 修复了与 defineCustomElement() API 相关的许多长期问题,并为使用 Vue 编写自定义元素添加了许多新功能:

  • 通过 configureApp 选项支持自定义元素的应用程序配置。
  • 添加 useHost()useShadowRoot()this.$host API,用于访问自定义元素的宿主元素和影子根。
  • 支持通过传递 shadowRoot: false 来在没有 Shadow DOM 的情况下挂载自定义元素。
  • 支持提供 nonce 选项,该选项将附加到自定义元素注入的 <style> 标签。

这些新的仅自定义元素选项可以通过第二个参数传递给 defineCustomElement

import MyElement from './MyElement.ce.vue'
defineCustomElements(MyElement, {
  shadowRoot: false,
  nonce: 'xxx',
  configureApp(app) {
    app.config.errorHandler = ...
  }
})

其他值得注意的特性

useTemplateRef()

3.5 引入了一种通过 useTemplateRef() API 获取 模板引用 的新方法:

<script setup>
import { useTemplateRef } from 'vue'
const inputRef = useTemplateRef('input')
</script>
<template>
  <input ref="input">
</template>

在 3.5 之前,我们推荐使用与静态 ref 属性匹配的变量名的普通 refs。旧方法要求 ref 属性能够被编译器分析,因此仅限于静态 ref 属性。相比之下,useTemplateRef() 通过运行时字符串 ID 匹配 refs,因此支持动态 ref 绑定到变化的 ID。

@vue/language-tools 2.1 还实现了 对新语法的特殊支持,因此您将在使用 useTemplateRef() 时根据模板中 ref 属性的存在获得自动完成和警告:

解构属性的内联提示

延迟传送

内置 <Teleport> 组件的一个已知限制是,传送目标元素必须在传送组件挂载时存在。这阻止了用户将内容传送到 Vue 渲染的其他元素中。

在 3.5 中,我们为 <Teleport> 引入了一个 defer 属性,它将在当前渲染周期后挂载,现在这将有效:

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

这种行为需要 defer 属性,因为默认行为需要向后兼容。

详情:PR#11387

onWatcherCleanup()

3.5 引入了一个全局导入的 API onWatcherCleanup(),用于在观察者中注册清理回调:

import { watch, onWatcherCleanup } from 'vue'
watch(id, (newId) => {
  const controller = new AbortController()
  fetch(`/api/${newId}`, { signal: controller.signal }).then(() => {
    // 回调逻辑
  })
  onWatcherCleanup(() => {
    // 中止陈旧请求
    controller.abort()
  })
})
分享于 2024-09-07

访问量 16

预览图片