Vue 3.3 发布了,来看看有哪些更新~
↓推荐关注↓
作者:@尤雨溪
译者:公号 — 若川视野
原文链接:
https://blog.vuejs.org/posts/vue-3-3
今天,我们很高兴地宣布发布 Vue 3.3
“浪客剑心”!
此版本专注于开发人员体验改进-特别是SFC<script setup>
与TypeScript的使用。与Vue语言工具[1](以前称为Volar)的1.6版本一起,我们在将Vue与TypeScript一起使用时解决了许多长期存在的痛点。这篇文章概述了3.3中突出显示的功能。有关更改的完整列表,请参阅GitHub上的完整更改日志[2]。
依赖性更新升级到3.3时,建议也更新以下依赖项:
volar / vue-tsc@^1.6.4
vite@^4.3.5
@vitejs/plugin-vue@^4.2.0
vue-loader@^17.1.0(如果使用webpack或vue-cli)
\<脚本设置> + TypeScript DX改进[3]
宏中的导入和复杂类型支持[4] 通用组件[5] 更符合人体工程学的定义Emits[6] 带有定义插槽的类型插槽[7] 实验特征[8]
响应式 props 解构[9] 定义模型[10] 其他值得注意的功能[11]
定义选项[12] 使用toRef和toValue提供更好的Getter支持[13] JSX导入源支持[14] 维护基础设施改进[15]
1<script setup>
+ TypeScript DX改进
宏中的导入和复杂类型支持
以前,defineProps
和defineEmits
的类型参数位置中使用的类型仅限于本地类型,并且仅支持类型文字和接口。这是因为Vue需要能够分析 props 接口上的属性,以便生成相应的运行时选项。这个限制现在在3.3中得到了解决。编译器现在可以解析导入的类型,并支持一组有限的复杂类型:
vue
<script setup lang="ts">
import type { Props } from './foo'
// imported + intersection type
defineProps<Props & { extraProp?: string }>()
</script>
请注意,复杂类型的支持是基于AST的,因此不是100%全面的。一些需要实际类型分析的复杂类型,例如条件类型,不受支持。您可以为单个 prop 的类型使用条件类型,但不能使用整个 prop 对象。
详情:PR#8083[16]
通用组件
使用<script setup>
的组件现在可以通过generic
属性接受通用类型参数:
vue
<script setup lang="ts" generic="T">
defineProps<{
items: T[]
selected: T
}>()
</script>
generic
的值与TypeScript中<...>
之间的参数列表完全相同。例如,您可以使用多个参数、extends
约束、默认类型和引用导入的类型:
vue
<script setup lang="ts" generic="T extends string | number, U extends Item">
import type { Item } from './types'
defineProps<{
id: T
list: U[]
}>()
</script>
此功能以前需要显式选择加入,但现在在最新版本的volar / vue-tsc中默认启用。
讨论:RFC#436[17] 相关:通用`defineComponent()`\-PR#7963[18]
更符合人体工程学defineEmits
以前,defineEmits
的类型参数仅支持调用签名语法:
ts
// BEFORE
const emit = defineEmits<{
(e: 'foo', id: number): void
(e: 'bar', name: string, ...rest: any[]): void
}>()
The type matches the return type foremit
, but is a bit verbose and awkward to write. 3.3 introduces a more ergonomic way of declaring emits with types:
ts
// AFTER
const emit = defineEmits<{
foo: [id: number]
bar: [name: string, ...rest: any[]]
}>()
在类型字面值中,键是事件名称,值是指定附加参数的数组类型。虽然不是必需的,但您可以使用标记的元组元素[19]来显式,如上例所示。仍然支持调用签名语法。
键入的插槽defineSlots
新的defineSlots
宏可用于声明预期插槽及其各自的预期插槽prop:
vue
<script setup lang="ts">
defineSlots<{
default?: (props: { msg: string }) => any
item?: (props: { id: number }) => any
}>()
</script>
defineSlots()
只接受类型参数,不接受运行时参数。类型参数应该是类型文字,其中属性键是插槽名称,值是插槽函数。该函数的第一个参数是插槽期望接收的prop,其类型将用于模板中的插槽 prop。defineSlots
的返回值与useSlots
返回的插槽对象相同。目前的一些限制:
所需的插槽检查尚未在volar / vue-tsc中实现。 插槽函数返回类型目前被忽略,可以是 any
,但我们将来可能会利用它进行插槽内容检查。
还有一个相应的slots
选项用于defineComponent
使用。这两个API都没有运行时影响,纯粹作为IDE和vue-tsc
的类型提示。
详情:PR#7982[20]
2实验特征
响应式 prop 解构
以前是现已放弃的响应性变换的一部分,响应式的解构已被拆分为一个单独的功能。该功能允许非结构化的prop保留响应性,并提供了一种更符合人体工程学的方式来声明 props 默认值:
vue
<script setup>
import { watchEffect } from 'vue'
const { msg = 'hello' } = defineProps(['msg'])
watchEffect(() => {
// accessing `msg` in watchers and computed getters
// tracks it as a dependency, just like accessing `props.msg`
console.log(`msg is: ${msg}`)
})
</script>
<template>{{ msg }}</template>
此功能是实验性的,需要明确选择加入。
详情:RFC#502[21]
defineModel
以前,为了使组件支持与v-model
双向绑定,它需要(1)声明prop,(2)在打算更新prop时发出相应的update:propName
事件:
vue
<!-- BEFORE -->
<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
console.log(props.modelValue)
function onInput(e) {
emit('update:modelValue', e.target.value)
}
</script>
<template>
<input :value="modelValue" @input="onInput" />
</template>
3.3简化了使用新的defineModel
宏的使用。宏会自动注册一个Props,并返回一个可以直接突变的引用:
vue
<!-- AFTER -->
<script setup>
const modelValue = defineModel()
console.log(modelValue.value)
</script>
<template>
<input v-model="modelValue" />
</template>
此功能是实验性的,需要明确选择加入。
详细信息:RFC#503[22]
3其他值得注意的功能
defineOptions
新的defineOptions
宏允许直接在<script setup>
声明组件选项,而无需单独的<script>
块:
vue
<script setup>
defineOptions({ inheritAttrs: false })
</script>
使用toRef
和更好的Getter支持toValue
toRef
已增强,以支持将值/获取器/现有引用标准化为引用:
js
// equivalent to ref(1)
toRef(1)
// creates a readonly ref that calls the getter on .value access
toRef(() => props.foo)
// returns existing refs as-is
toRef(existingRef)
使用getter调用toRef
类似于computed
,但当getter只是在没有昂贵计算的情况下执行属性访问时,效率会更高。新的toValue
实用程序方法提供了相反的,将值/获取器/引用标准化为值:
toValue(1) // --> 1
toValue(ref(1)) // --> 1
toValue(() => 1) // --> 1
toValue
可以在可组合物中代替unref
,以便您的可组合物可以接受获取者作为响应性数据源:
// before: allocating unnecessary intermediate refs
useFeature(computed(() => props.foo))
useFeature(toRef(props, 'foo'))
// after: more efficient and succinct
useFeature(() => props.foo)
toRef
和toValue
之间的关系与ref
和unref
之间的关系相似,主要区别是getter函数的特殊处理。
详情:PR#7997[23]
JSX导入源支持
目前,Vue的类型会自动注册全局JSX类型。这可能会导致与其他需要JSX类型推理的库一起使用的冲突,特别是React。从3.3开始,Vue支持通过TypeScript的jsxImportSource[24]选项指定JSX命名空间。这允许用户根据他们的用例选择全局或每个文件选择加入。为了向后兼容,3.3仍然在全球范围内注册JSX命名空间。我们计划在3.4中删除默认的全局注册。如果您将TSX与Vue一起使用,您应该在升级到3.3后将显式jsxImportSource
添加到tsconfig.json
,以避免在3.4中损坏。
4维护基础设施改进
此版本基于许多维护基础设施改进,使我们能够更自信地更快地移动:
通过将类型检查与 rollup
构建分开,并从rollup-plugin-typescript2
移动到rollup-plugin-esbuild
,构建速度快10倍。通过从Jest 迁移到 Vitest[25] 来加快测试速度。 通过从 @microsoft/api-extractor
移动到rollup-plugin-dts
更快地生成类型。通过ecosystem-ci [26]进行综合回归测试-在发布前捕获主要生态系统依赖项的回归!
按照计划,我们的目标是在2023年开始发布更小、更频繁的功能。敬请期待!
参考资料
Vue语言工具: https://github.com/vuejs/language-tools/
[2]上的完整更改日志: https://github.com/vuejs/core/blob/main/CHANGELOG.md#330-2023-05-08
[3]<脚本设置> + TypeScript DX改进: https://blog.vuejs.org/posts/vue-3-3#script-setup-typescript-dx-improvements
[4]宏中的导入和复杂类型支持: https://blog.vuejs.org/posts/vue-3-3#imported-and-complex-types-support-in-macros
[5]通用组件: https://blog.vuejs.org/posts/vue-3-3#generic-components
[6]更符合人体工程学的定义Emits: https://blog.vuejs.org/posts/vue-3-3#more-ergonomic-defineemits
[7]带有定义插槽的类型插槽: https://blog.vuejs.org/posts/vue-3-3#typed-slots-with-defineslots
[8]实验特征: https://blog.vuejs.org/posts/vue-3-3#experimental-features
[9]响应式 props 解构: https://blog.vuejs.org/posts/vue-3-3#reactive-props-destructure
[10]定义模型: https://blog.vuejs.org/posts/vue-3-3#definemodel
[11]其他值得注意的功能: https://blog.vuejs.org/posts/vue-3-3#other-notable-features
[12]定义选项: https://blog.vuejs.org/posts/vue-3-3#defineoptions
[13]使用toRef和toValue提供更好的Getter支持: https://blog.vuejs.org/posts/vue-3-3#better-getter-support-with-toref-and-tovalue
[14]JSX导入源支持: https://blog.vuejs.org/posts/vue-3-3#jsx-import-source-support
[15]维护基础设施改进: https://blog.vuejs.org/posts/vue-3-3#maintenance-infrastructure-improvements
[16]PR#8083: https://github.com/vuejs/core/pull/8083
[17]#436: https://github.com/vuejs/rfcs/discussions/436
[18]通用defineComponent()
-PR#7963: https://github.com/vuejs/core/pull/7963
标记的元组元素: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-0.html#labeled-tuple-elements
[20]PR#7982: https://github.com/vuejs/core/issues/7982
[21]RFC#502: https://github.com/vuejs/rfcs/discussions/502
[22]#503: https://github.com/vuejs/rfcs/discussions/503
[23]PR#7997: https://github.com/vuejs/core/pull/7997
[24]jsxImportSource: https://www.typescriptlang.org/tsconfig#jsxImportSource
[25]Vitest: https://vitest.dev/
[26]ecosystem-ci : https://github.com/vuejs/ecosystem-ci
- EOF -
加主页君微信,不仅前端技能+1
主页君日常还会在个人微信分享前端开发学习资源和技术文章精选,不定期分享一些有意思的活动、岗位内推以及如何用技术做业余项目
加个微信,打开一扇窗
1、前端开发走向终结
觉得本文对你有帮助?请分享给更多人
推荐关注「前端大全」,提升前端技能
点赞和在看就是最大的支持❤️