大家好,我是双越老师,也是开源富文本编辑器 wangEditor 作者。
近期我正在致力于开发一个 Node 全栈 AIGC 知识库项目 划水AI ,包括文档管理、AI 写作、协同编辑等功能。真实上线,持续维护,有兴趣的同学欢迎点进去看看~
今天我来翻译一下 Vue 作者 尤雨溪 写的《Announcing Vue 3.5》 ,原文地址 blog.vuejs.org/posts/vue-3…
这不是一键机器翻译的,而是我自己一行一行亲自翻译过来的。第一保证可读性,第二我会在一些地方做出自己的解释。机器翻译的会很生硬,而且专业词汇会翻译错误,你一眼就能看出来。
Let's go.
2024.9.1
宣布 Vue3.5
今天我们很开心的宣布 Vue3.5 版本的发布,代号是“Tengen Toppa Gurren Lagann”
译者:这个代号貌似是动漫相关的,我不看动漫所以不了解,有知道的朋友可以评论解释一下。
这次小版本(minor release)升级没有断崖式的更新,既包含内部的升级优化,也包含一些有用的新功能。本文主要介绍一些重要功能,完整的更新和功能,从参考这里 the full changelog on GitHub
Reactivity System Optimizations 响应式系统优化
在 3.5 版本中,Vue 响应式系统又经历了一次重构,继续优化性能,内存使用率降低了 56% ,并且没有使用上的改变。这次重构也解决了在 SSR 期间因计算挂起而导致的陈旧的 computed 值和内存问题。
此外,3.5 版本还优化了针对大型数据、深层次数组的响应式追踪,在某些场景下最快有 10 倍的提速。
译者:这是内部改进,对使用者无影响。
Reactive Props Destructure 响应式属性解构
响应式属性解构在 3.5 版本中已经稳定了。现在这个功能已经可以默认使用了,在 <script setup>
中使用 defineProps
获取的变量并解构,支持响应式。而且,这个功能还简化了使用默认值来定义属性,直接使用 JS 原生的默认值语法。
之前
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
类似,监听一个属性解构变量,或者把他们传递给一个 compossable(译者:自定义 Hook)时,如果需要保持响应式,你需要用一个 getter(译者:一个函数,如下代码)包裹起来。
watch(count /* ... */)
// ^ results in compile-time error
watch(() => count /* ... */)
// ^ wrap in a getter, works as expected
// composables should normalize the input with `toValue()`
useDynamicCount(() => count)
想要区分属性解构变量和普通变量,@vue/language-tools
2.1 可以给出提示。
细节
SSR Improvements 服务端渲染的改进
3.5 版本带来了一些期待已久的 SSR 改进。
Lazy Hydration
现在,你可以自定义策略,控制异步组件什么时候被 hydrated ,在 defineAsyncComponent()
中使用 hydrate
API 来控制。例如,当它显示的时候(译者:即下面的 hydrateOnVisible()
返回值)才被 hydrated.
import { defineAsyncComponent, hydrateOnVisible } from 'vue'
const AsyncComp = defineAsyncComponent({
loader: () => import('./Comp.vue'),
hydrate: hydrateOnVisible()
})
这是一个比较基础的 API (译者:开发者不好直接使用),Nuxt 团队已经在此基础上封装了高级功能和语法糖,方便用户使用。
细节: PR#11458
useId()
useId()
可以生成唯一 ID ,在应用内不重复,而且可以跨服务端和客户端。可用于生成元素 ID 和 accessibility 属性,还可以在 SSR 中使用,这不会导致 hydration 不匹配。
译者:同一个数据客户端和服务端渲染不一致,和下文的 data-allow-mismatch
有关系。
<script setup>
import { useId } from 'vue'
const id = useId()
</script>
<template>
<form>
<label :for="id">Name:</label>
<input :id="id" type="text" />
</form>
</template>
细节: PR#11404
data-allow-mismatch
某些情况下,客户端的值和服务端的值难免会不一样(如日期时间),现在我们可以通过 data-allow-mismatch
属性来屏蔽 hydration 不匹配的警告提醒。(译者:允许这里的 mismatch)
<span data-allow-mismatch>{{ data.toLocaleString() }}</span>
你还可以制定允许哪些类型可以 mismatch 并且把这个类型值传递给 data-allow-mismatch
属性值,类型可以是 text
, children
, class
, style
, 和 attribute
。
Custom Elements Improvements 自定义元素的改进
3.5 版本修复了许多关于 defineCustomElement()
API 的长期存在的问题,并且增加了许多自定义元素的新功能。
- 支持自定义元素的 app 配置,通过
configureApp
选项 - 增加
useHost
,useShadowRoot
, 和this.$host
API 用于访问自定义元素的宿主元素和 shadow 根节点 - 传入
shadowRoot: false
,支持在没有 shadowDOM 时,渲染自定义元素 - 提供
nonce
选项,它会被添加由自定义元素注入的<style>
标签上
这些新的 custom-element-only (译者:只能用在自定义元素)选项可以添加到 defineCustomElement
的第二个参数。
import MyElement from './MyElement.ce.vue'
defineCustomElements(MyElement, {
shadowRoot: false,
nonce: 'xxx',
configureApp(app) {
app.config.errorHandler = ...
}
})
译者:Custom Elements 不太常用,我貌似还没用过呢,哈哈
Other Notable Features 其他重要功能
useTemplateRef()
3.5 版本介绍了一个新的方式去获取 Template Refs,通过 useTemplateRef
API
<script setup>
import { useTemplateRef } from 'vue'
const inputRef = useTemplateRef('input')
</script>
<template>
<input ref="input">
</template>
3.5 版本之前,我们推荐使用普通 ref
自己定义类型(译者:TS 类型)。之前的方式需要自定义定义 ref
以便编译器能理解,而且必须是静态类型。相比而言,useTemplateRef()
匹配运行时 ID ,因此支持动态绑定。(译者: 我也没搞定动态绑定啥意思,可能需要再看看文档和 demo)
译者:上面这一段我觉得翻译的不够精准细致,你可以自己去看原文。
@vue/language-tools
2.1 已经实现了 新语法的特殊支持,所以当你使用 useTemplateRef()
时候,它可以帮你自动完成和提示。
Deferred Teleport
对于 <Teleport>
组件,一个已知的限制就是:它在渲染时,它的目标元素必须存在。这可以防止用户传递内容给其他元素。
在 3.5 版本中,我们为 <Teleport>
组件增加了 defer
属性,这可以让它在下一轮渲染时加载这个组件,如下代码
<Teleport defer target="#container">...</Teleport>
<div id="container"></div>
这个特性需要 defer
属性,因为默认情况下我们要向后兼容。
细节: PR#11387
onWatcherCleanup()
3.5 新增了一个全局 API onWatcherCleanup()
可以在 watch 监听中注册一个 callback 回调函数。
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()
})
})
- 相关文档: 新的文档部分 Side Effect Cleanup
对于 3.5 版本综合的改动和功能,你可以参考 GitHub 全部改动记录.
Happy hacking!
结束。以上就是原文的全部翻译,希望对大家有帮助。
最后,如果想参与学习真实线上项目,请看看我开发的 Node 全栈 AIGC 知识库项目 划水AI。