Vue3.4发布啦!
前言
Vue3.4包含了一些实质性的内部改进——最主要的是重写了模板解析器,速度提高了两倍。它重构了reactivity,使得效果触发更加准确和高效。 还包含了许多API的质量改进,包括defineModel的稳定性以及传递props时类似es6的同名简写语法。
使用前可能需要的前置操作
为了充分利用3.4中的新功能,建议在升级到3.4时更新以下依赖项:
Volar / vue-tsc@^1.8.27 (必选)
@vitejs/plugin-vue@^5.0.0 (如果使用Vite)
nuxt@^3.9.0 (如果使用nuxt)
vue-loader@^17.4.0 (如果使用webpack或vue-cli)
如果你的Vue中使用了TSX,请检查: 全局JSX命名空间。确保没有使用任何已弃用的特性(如果使用了,控制台中会有警告提示)
核心特性
更快的解析器和改进的SFC构建性能
在3.4中,完全重写了模板解析器。以前,Vue使用依赖于许多正则表达式和提前查找的递归解析器。新的解析器使用基于htmlparser2中的状态机,它只迭代整个模板一次。对于所有大小的模板,解析器的速度始终是原来的两倍。 由于我们广泛的测试用例和生态系统,它也100%向后兼容Vue所有的用户。在将新的解析器与系统的其他部分集成时,我们还发现了一些进一步提高整体SFC编译性能的机会。在生成源映射的同时编译Vue SFC的脚本和模板部分时,基准测试显示了约44%的改进,因此3.4应该会使大多数使用Vue SFC的项目的构建速度更快。但是,请注意,Vue SFC编译只是实际项目中整个构建过程的一部分。与孤立的测试相比,端到端构建时间的最终增益可能要小得多。在Vue核心之外,新的解析器也将有利于Volar / vue-tsc的性能,以及需要解析Vue sfc或模板的社区插件,例如Vue Macros
更精进的Reactivity系统
3.4还对Reactivity进行了重构,目的是提高计算属性的重新计算效率。 为了说明改进的地方,让我们考虑以下场景:
const count = ref(0)
const isEven = computed(() => count.value % 2 === 0)
watchEffect(() => console.log(isEven.value)) // logs true
count.value = 2 // logs true again
在3.4之前,即使计算结果保持不变, watchEffect的回调将在每次计数时触发。在3.4的优化中,现在回调只有在计算结果实际发生变化时才会触发。此外,多个计算深度变化只触发同步效果一次。数组移位、不移位、拼接方法只触发一次。这应该可以减少许多场景中不必要的组件re-render,同时保持完全的向后兼容性。
defineModel
使用指南
从Vue 3.4开始,推荐的方法是使用defineModel()
<!-- Child.vue -->
<script setup>
const model = defineModel()
function update() {
model.value++
}
</script>
<template>
<div>父组件绑定v-model为: {{ model }}</div>
</template>
然后父节点可以用v-model绑定一个值:
<!-- Parent.vue -->
<Child v-model="count" />
defineModel()
返回的值是一个 ref。可以像任何其他 ref 一样被访问和修改,除了它充当父值和局部值之间的双向绑定:
- 它的 .value 与父 v-model 绑定的值同步;
- 当它被子组件修改时,也会导致父绑定值被更新。
这意味着你也可以使用 v-model 将这个 ref 绑定到一个原生输入元素上,使得原生输入元素变得easy,同时提供相同的 v-model
用法:
<script setup>
const model = defineModel()
</script>
<template>
<input v-model="model" />
</template>
defineModel
变更为稳定版API
defineModel
是一个新的<script setup>
成员,旨在简化v-model
的组件的实现。之前在3.3中作为一个实验特性发布,现在3.4中升级到稳定状态。它现在还将为使用v-model
修饰符提供了更好的支持。
defineModel
可以用来声明一个双向绑定属性,它可以通过父组件的 v-model 来使用。在上面的 defineModel
指南中讨论了示例用法。在底层,defineModel
实际上是声明了一个 model 属性和一个对应值的更新事件:
<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>
<template>
<input
:value="props.modelValue"
@input="emit('update:modelValue', $event.target.value)"
/>
</template>
如果第一个参数是个字符串,它将被用作属性名称;否则,属性名称将默认为 "modelValue"。在这两种情况下,你还可以传递一个额外的对象,该对象可以包括属性的选项和模型引用的值转换选项。
// 声明 "modelValue" prop, 由父节点通过v-model消费
const model = defineModel()
// 或者: 用options prop 声明 "modelValue"
const model = defineModel({ type: String })
// 当改变时触发 "update:modelValue"
model.value = 'hello'
// 声明 "count" prop, 由父节点通过v-model:count消费
const count = defineModel('count')
// 或者: 用options prop 声明 "count"
const count = defineModel('count', { type: Number, default: 0, required: true })
function inc() {
// 当更新时触发 "update:count"
count.value++
}
要访问与 v-model 指令一起使用的修饰符,我们可以像这样解构 defineModel() 的返回值:
const [modelValue, modelModifiers] = defineModel() // 与 v-model.trim 对应
if (modelModifiers.trim) { // ... }
当存在修饰符时,我们可能需要在读取值或将其同步回父组件时转换该值。我们可以通过使用 get 和 set 转换器选项来实现这一点:
const [modelValue, modelModifiers] = defineModel({
// get() 被省略,因为这里不需要
set(value) {
// 如果使用 .trim 修饰符, 返回trim后的值
if (modelModifiers.trim) {
return value.trim()
}
// 其余情况, 按原样返回值
return value
}
})
TypeScript中使用
就像 defineProps 和 defineEmits 一样,defineModel 也可以接收类型参数来指定模型值和修饰符的类型:
const modelValue = defineModel<string>()
// ^? Ref<string | undefined>
// default model with options, required removes possible undefined values
const modelValue = defineModel<string>({ required: true })
// ^? Ref<string>
const [modelValue, modifiers] = defineModel<string, 'trim' | 'uppercase'>()
// ^? Record<'trim' | 'uppercase', true | undefined>
v-bind
简化语法
原来的语法:
<img :id="id" :src="src" :alt="alt">
你现在可以缩短它:
<img :id :src :alt>
在过去,这个特性我们经常被社区的小伙伴们要求完成。
最初,我们担心它的用法会与boolean属性混淆。然而,在重新审视了这个特性之后,考虑到它的动态特性,我们现在认为v-bind的行为更像JavaScript是有意义的,所以我们将其进行了实现。
改进SSR场景下注水(hydration)时不匹配问题的具体检查与警告
3.4发布了一些对注水(hydration)时不匹配错误消息的改进:
改进了措辞的清晰度,消息现在包含了问题所在的DOM节点,因此可以在页面或元素面板中快速定位到问题。hydration不匹配检查现在也适用于类、样式和其他动态绑定属性。
此外,3.4还添加了一个新的编译时标志,VUE_PROD_HYDRATION_MISMATCH_DETAILS,它可以用于强制展示hydration过程中的不匹配错误(包括在生产环境下的细节)
错误提示的映射优化
为了减小包的大小,Vue在生产构建中删除了较长的错误消息字符串。 这意味着在生产环境中将接收到简短的错误提示,如果不深入Vue的源代码,就很难解决这些错误。 为了改进这一点,vue在文档中添加了一个生产错误参考页。 错误码是通过最新版本的Vue稳定版自动生成的
彻底弃用的特性
全局JSX命名空间
从3.4开始,Vue不再默认注册全局JSX名称空间。这对于避免与React的全局命名空间冲突是友好的,这样两个库的TSX就可以共存于同一个项目中。
这应该不会影响使用最新版Volar的sfc用户。如果你正在使用TSX,有两个选项:
在tsconfig中显式地将jsxImportSource设置为'vue'。
在升级到3.4之前。你还可以通过在文件顶部添加/* @jsxImportSource vue */注释来选择每个文件。
如果你的代码依赖于全局JSX命名空间的存在,例如使用像JSX这样的类型。元素等,您可以通过显式引用vue/jsx来保留3.4之前的全局行为,它注册了全局jsx名称空间。请注意,这是一个小版本中破坏性的更改
移除v-is
v-is
指令在3.3被移除. 3.4开始请使用 is=vue:语法<tr is="vue:my-row-component"></tr>
结语
以上就是3.4更新的大致内容了!
内容不当之处还请理解(机翻 + 校对)
译自:
转载自:https://juejin.cn/post/7320075000701272103