Vue 3.5发布,新增几个新用法
响应式 Props 解构
Reactive Props Destruction 已在 3.5 中稳定下来。现在默认启用该功能,从 <script setup>
中的 defineProps 调用解构的变量现在是响应性的。值得注意的是,此功能通过利用 JavaScript 的原生默认值语法,显着简化了使用默认值声明 props 的过程。
vue3.5前响应式解构props用法
vue3.5响应式解构props方法
对解构变量(例如count)的访问会由编译器自动编译到 props.count 中,因此在访问时会跟踪它们。与props.count 类似,观察解构的 prop 变量或将其传递到可组合项同时保留反应性需要将其包装在 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)
2
3
4
5
6
7
8
useId()
useId()
是一个 API,可用于生成每个应用程序唯一的 ID,并保证在服务器和客户端渲染中保持稳定。它们可用于生成表单元素和可访问性属性的 ID,并可在 SSR 应用程序中使用,而不会导致水合作用不匹配。
结合 app.config.idPrefix
前缀,使开发者可以更轻松地管理应用中的 ID,尤其是在多应用场景下能够避免 ID 冲突。
<script setup>
import { useId } from 'vue'
const id = useId()
</script>
<template>
<form>
<label :for="id">Name:</label>
<input :id="id" type="text" />
</form>
</template>
2
3
4
5
6
7
8
9
10
11
12
自定义元素改进
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 = function() {
}
}
})
2
3
4
5
6
7
8
9
10
11
12
useTemplateRef()
3.5 引入了一种通过 useTemplateRef() API 获取模板引用的新方法:
<script setup>
import { useTemplateRef } from 'vue'
const inputRef = useTemplateRef('input')
const divRef = useTemplateRef<HTMLDivElement>('div')
</script>
<template>
<input ref="input">
<div ref="div">a</div>
</template>
2
3
4
5
6
7
8
9
10
11
在 3.5 之前,我们建议使用纯引用,其变量名称与静态 ref 属性匹配。旧方法要求编译器可以分析 ref 属性,因此仅限于静态 ref 属性。相比之下, useTemplateRef() 通过运行时字符串 ID 匹配引用,因此支持动态引用绑定到更改的 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>
2
此行为需要defer属性,因为默认行为需要向后兼容。
onWatcherCleanup()
3.5 引入了全局导入的 API onWatcherCleanup()
,用于在观察者中注册清理回调:
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()
})
})
2
3
4
5
6
7
8
9
10
11
12
13
14
import { watch, onWatcherCleanup } from 'vue'
watch(id, (newId) => {
const { response, cancel } = doAsyncWork(newId)
// 如果之前的请求还没有完成的话
onWatcherCleanup(cancel)
})
2
3
4
5
6
7
Lazy Hydration
异步组件现在可以通过 defineAsyncComponent()
API 的 hydrate 选项指定策略来控制何时应进行 Hydrated
。例如,仅在组件可见时对其进行水合:
import { defineAsyncComponent, hydrateOnVisible } from 'vue'
const AsyncComp = defineAsyncComponent({
loader: () => import('./Comp.vue'),
hydrate: hydrateOnVisible()
})
2
3
4
5
6
核心 API 有意设置为较低级别,Nuxt 团队已经在此功能的基础上构建了更高级别的语法糖。
watch的暂停和恢复
const { stop, pause, resume } = watchEffect(() => {})
// 暂时暂停观察者
pause()
// 恢复观察者
resume()
// 停止观察
stop()
2
3
4
5
6
7
8
9
10