今天,我们非常兴奋地宣布发布 Vue 3.5 "Tengen Toppa Gurren Lagann"!
这是一个小版本更新,不包含破坏性变更,同时包含内部改进和有用的新功能。我们将在这篇博客文章中介绍一些亮点——完整的更改和新功能列表请参阅 GitHub 上的完整更新日志。
响应式系统优化
在 3.5 版本中,Vue 的响应式系统进行了又一次重大重构,在没有行为变更的情况下,性能得到了提升,内存使用显著改善(减少了 56%)。此重构还解决了 SSR 中由于悬挂计算属性导致的过时计算值和内存问题。
此外,3.5 版本还针对大型、深度响应式数组优化了反应式跟踪,在某些情况下,使这些操作的速度提高了 10 倍。
响应式属性解构
响应式属性解构在 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 版本提供了一个可选设置,可以为它们启用内联提示:
解构属性的内联提示
详细信息:
SSR(服务端渲染)改进
3.5 带来了几项长期请求的服务端渲染改进。
懒加载 Hydration
异步组件现在可以通过 defineAsyncComponent()
API 的 hydrate
选项指定何时进行 Hydration。例如,只在组件可见时进行 Hydration:
import { defineAsyncComponent, hydrateOnVisible } from 'vue'
const AsyncComp = defineAsyncComponent({
loader: () => import('./Comp.vue'),
hydrate: hydrateOnVisible()
})
核心 API 刻意保持低级别,Nuxt 团队已经在此功能之上构建了更高级别的语法糖。
详细信息:PR#11458
useId()
useId()
是一个 API,用于生成在服务器和客户端渲染之间保证稳定的唯一应用程序 ID。这些 ID 可以用于表单元素和可访问性属性,并且在 SSR 应用程序中使用时不会导致 Hydration 不匹配:
<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
属性来抑制结果中的 Hydration 不匹配警告:
<span data-allow-mismatch>{{ data.toLocaleString() }}</span>
您还可以通过为属性提供值来限制允许的 mismatch 类型,可能的值包括 text
、children
、class
、style
和 attribute
。
自定义元素改进
3.5 修复了许多与 defineCustomElement()
API 相关的长期问题,并为使用 Vue 编写自定义元素添加了许多新功能:
- 通过
configureApp
选项支持为自定义元素配置应用程序。 - 添加了
useHost()
、useShadowRoot()
和this.$host
API,用于访问自定义元素的主机元素和 Shadow Root。 - 支持通过传递
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 获取 Template Refs 的新方法:
<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
属性的存在获得自动完成和警告:
解构属性的内联提示
延迟传送(Deferred Teleport)
内置 <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()
})
})
相关:新文档部分关于副作用清理
网友评论