likes
comments
collection
share

Vue3.4发布啦!

作者站长头像
站长
· 阅读数 50

前言

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更新的大致内容了!

内容不当之处还请理解(机翻 + 校对)

译自:

The Vue Point

Revised Component v-model section

defineModel API reference

转载自:https://juejin.cn/post/7320075000701272103
评论
请登录