Vue 3.3带来了很多新特性,但新特性也有新坑。

本文记录我在使用Vue 3.3新特性时踩过的坑,包括defineProps泛型、defineEmits、defineOptions、响应式props解构、宏导入,以及解决方法。

一、升级Vue 3.3的经历

1. 为什么升级

我升级Vue 3.3,是因为新特性太诱人了。

  • defineProps支持泛型
  • defineEmits更简洁
  • defineOptions
  • 响应式props解构
  • 这些特性让代码更简洁

新特性,让我迫不及待地升级。

2. 升级的过程

升级的过程:

  • 升级vue版本
  • 升级vite插件
  • 升级volar
  • 改代码
  • 测试

看起来简单,实际踩了很多坑。

3. 熬夜的夜晚

为了这些新特性,我熬了好几个夜。

  • 类型报错
  • 运行时报错
  • 构建报错
  • 各种奇怪的问题
  • 但最终都解决了

每个坑,都是一次学习。

二、defineProps泛型的坑

1. 坑一:泛型语法不熟悉

第一个坑:泛型语法不熟悉。

Vue 3.3之前:

const props = defineProps({
    name: {
        type: String,
        required: true
    },
    age: Number
})

Vue 3.3泛型语法:

const props = defineProps<{
    name: string
    age?: number
}>()
  • 刚开始不习惯
  • 类型和运行时的区别
  • 后来觉得很好用

泛型语法,需要适应。

2. 坑二:withDefaults的位置

第二个坑:withDefaults的位置。

错误写法:

const props = withDefaults<{
    name: string
    age?: number
}>({
    age: 18
})

正确写法:

const props = withDefaults(defineProps<{
    name: string
    age?: number
}>(), {
    age: 18
})
  • withDefaults要包裹defineProps
  • 刚开始写错了
  • 类型报错
  • 后来才搞清楚

withDefaults,位置很重要。

3. 坑三:泛型组件

第三个坑:泛型组件。

<script setup generic="T">
const props = defineProps<{
    items: T[]
    selected: T
}>()
</script>
  • 泛型组件是Vue 3.3的新特性
  • 但工具支持还不完善
  • Volar有时候报错
  • 需要升级工具
  • 需要注意版本

泛型组件,很强大但也有坑。

4. 坑四:外部类型导入

第四个坑:外部类型导入。

// types.ts
export interface User {
    id: number
    name: string
}
<script setup>
import type { User } from './types'

const props = defineProps<{
    user: User
}>()
</script>
  • 外部类型可以用
  • 但要注意是type import
  • 不能导入值
  • 否则会报错

外部类型,要注意导入方式。

三、defineEmits的坑

1. 坑一:新语法不熟悉

第一个坑:defineEmits新语法不熟悉。

旧语法:

const emit = defineEmits(['update', 'close'])

新语法:

const emit = defineEmits<{
    (e: 'update', value: string): void
    (e: 'close'): void
}>()
  • 类型声明方式
  • 刚开始不习惯
  • 后来觉得类型提示很好

新语法,需要适应。

2. 坑二:emit的类型提示

第二个坑:emit的类型提示。

  • 用了类型声明后
  • emit的时候有类型提示
  • 参数类型不对会报错
  • 很好用
  • 但要注意类型正确

类型提示,是新语法的优势。

3. 坑三:和v-model的配合

第三个坑:和v-model的配合。

const emit = defineEmits<{
    (e: 'update:modelValue', value: string): void
}>()

const props = defineProps<{
    modelValue: string
}>()
  • v-model的事件名
  • 要和props对应
  • update:modelValue
  • 不要写错

v-model,要注意命名。

四、defineOptions的坑

1. 坑一:不知道有这个宏

第一个坑:不知道有defineOptions。

  • Vue 3.3新增的
  • 用来定义组件选项
  • 比如name、inheritAttrs
  • 以前要单独写一个script
  • 现在一个宏搞定

defineOptions,很方便。

2. 坑二:用法

defineOptions的用法:

<script setup>
defineOptions({
    name: 'MyComponent',
    inheritAttrs: false
})
</script>
  • 可以定义name
  • 可以定义inheritAttrs
  • 可以定义其他选项
  • 很方便

defineOptions,简化了代码。

3. 坑三:和name的配合

第三个坑:和name的配合。

  • 以前define setup的组件没有name
  • 递归组件需要name
  • 现在用defineOptions定义name
  • 解决了递归组件的问题

name,终于方便了。

五、响应式props解构的坑

1. 坑一:解构丢失响应式

第一个坑:解构丢失响应式。

Vue 3.3之前:

const props = defineProps<{ count: number }>()
const { count } = props  // 丢失响应式

Vue 3.3:

const { count } = defineProps<{ count: number }>()
// 保持响应式
  • Vue 3.3支持响应式解构
  • 但要注意是从defineProps解构
  • 不是从props变量解构
  • 刚开始搞错了

响应式解构,要注意来源。

2. 坑二:默认值

第二个坑:解构时的默认值。

const { count = 0 } = defineProps<{ count?: number }>()
  • 解构时可以设默认值
  • 但和withDefaults的关系
  • 不要同时用
  • 选择一种方式

默认值,要注意方式。

3. 坑三:工具支持

第三个坑:工具支持。

  • 响应式解构是新特性
  • Volar需要升级
  • ESLint插件需要升级
  • 旧版本可能报错
  • 要注意工具版本

工具,要跟上版本。

六、宏导入的坑

1. 坑一:不知道可以导入

第一个坑:不知道宏可以导入。

  • Vue 3.3支持宏导入
  • defineProps、defineEmits等
  • 可以从vue导入
  • 但通常不需要
  • 自动可用

宏导入,是新特性。

2. 坑二:什么时候需要导入

什么时候需要导入?

  • 通常不需要
  • 自动可用
  • 但在某些配置下
  • 可能需要显式导入
  • 看项目配置

宏导入,看情况。

七、工具链的坑

1. 坑一:Volar版本

第一个坑:Volar版本。

  • Vue 3.3的新特性
  • 需要新版Volar支持
  • 旧版本会报错
  • 要升级Volar
  • 要注意版本兼容

Volar,要及时升级。

2. 坑二:vite插件版本

第二个坑:vite插件版本。

  • @vitejs/plugin-vue
  • 需要新版本
  • 旧版本不支持新特性
  • 要升级
  • 要注意兼容

vite插件,要跟上。

3. 坑三:ESLint插件

第三个坑:ESLint插件。

  • eslint-plugin-vue
  • 需要新版本
  • 旧版本可能误报
  • 要升级
  • 要调整规则

ESLint,也要升级。

4. 坑四:TypeScript版本

第四个坑:TypeScript版本。

  • 新特性需要新版TS
  • 旧版本可能不支持
  • 要升级TS
  • 要注意配置

TypeScript,是基础。

八、我的经验总结

1. 升级前看文档

第一个经验:升级前看文档。

  • 看官方升级指南
  • 看新特性文档
  • 看breaking changes
  • 了解可能的坑
  • 做好准备

文档,是最好的老师。

2. 小步升级

第二个经验:小步升级。

  • 不要一次改太多
  • 先升级依赖
  • 再改代码
  • 逐步使用新特性
  • 每步都测试

小步,降低风险。

3. 工具先升级

第三个经验:工具先升级。

  • Volar
  • vite插件
  • ESLint
  • TypeScript
  • 工具先升级,再改代码

工具,是基础。

4. 保留旧写法

第四个经验:保留旧写法。

  • 新特性可以慢慢用
  • 不要全部改掉
  • 旧写法依然支持
  • 逐步迁移
  • 降低风险

渐进式,是安全的方式。

5. 遇到问题查issue

第五个经验:遇到问题查issue。

  • 新特性可能有bug
  • 查GitHub issue
  • 看有没有人遇到同样的问题
  • 看解决方案
  • 必要时提issue

社区,是强大的后盾。

九、写在最后

Vue 3.3新特性踩坑记,那些让我熬夜的问题。

defineProps泛型的坑:语法不熟悉、withDefaults位置、泛型组件、外部类型导入。defineEmits的坑:新语法、类型提示、v-model配合。defineOptions的坑:不知道有这个宏、用法、name配合。响应式props解构的坑:解构丢失响应式、默认值、工具支持。宏导入的坑:不知道可以导入、什么时候需要导入。工具链的坑:Volar版本、vite插件版本、ESLint插件、TypeScript版本。

2023年了,Vue 3.3带来了很多令人兴奋的新特性。新特性意味着新的可能性,也意味着新的坑。不要害怕踩坑,每个坑都是一次学习。升级前看文档,小步升级,工具先升级,保留旧写法,遇到问题查issue,你也能顺利升级。

最后,用一句话总结:"新特性有新坑,但也有新可能。仔细看文档,小步升级,工具先行,你也能用上Vue 3.3的新特性。"

希望我的踩坑记,能帮你少熬几个夜。