Vue3 迁移指南
概述
这是本人对组织版项目 Vue3 重构过程的相关总结。
官方迁移指南清晰地列出了 Vue2 到 Vue3 迁移需要注意的 breaking changes 和相关变动。其中有部分细节在实际重构时需要注意,下面展开讲讲。
可以提前开始做的
项目仍处于 Vue 2.x 时即可开始的部分重构内容,可以使重构周期的工作量曲线更加平滑。
- 迁移所有过滤器
filters,用函数方法替换 - 事件总线替换为
mitt - 状态管理从
Vuex迁移到Pinia 2.x
大致流程
- 本地执行
npm create vue临时新建一个 Vue3 项目,在老项目中对齐新模板的基础文件结构和依赖包; - 删除 lock 和 node_modules,更新适配 Vue3 的依赖包,尝试
npm install,处理包冲突问题; - 尝试
npm run dev,开始修复报错问题:- 建议先 vite 添加配置
logLevel: 'error',忽略警告信息; - vue-router/vuedraggable/vue-i18n 等所有
Vue2 依赖包的升级; - 执行
npm run lint,部分错误会被自动修复,对着控制台错误信息逐一修复报错
- 建议先 vite 添加配置
潜在坑点
组件 v-model 变化
问题:迁移时不能直接全局替换,比如 Option 组件 props 依旧是 value 属性,input 原生标签依旧是 value/@input。
解决:需要全局搜索 value/@input 后仔细核对替换。
<XXX v-model="form"></XXX>
<!-- Vue 2 等价于 -->
<XXX :value="form" @input="form = $event"></XXX>
<!-- Vue 3 等价于 -->
<XXX :model-value="form" @update:modelValue="form = $event"></XXX>
组件 class 继承问题
问题:template 内支持了多个子节点/Teleport 功能,有潜在的样式继承问题。
解决:
- vite 添加配置;
vue({
template: {
compilerOptions: {
whitespace: 'preserve',
comments: false, // template 内忽略注释节点
},
},
}),
- 注意 heywhale-ui
Drawer/Model/Dropdown如果样式有问题的话可以把 class 改为 class-name。
<Drawer class="xxx-drawer"></Drawer>
<!-- class 有问题的话换成 class-name -->
<Drawer class-name="xxx-drawer"></Drawer>
HTML Element attribute 行为变化
https://v3-migration.vuejs.org/zh/breaking-changes/attribute-coercion.html
问题:原生 html 的非官方 attribute 属性值为 false 时,在 vue 3 里不会被移除。
解决:避免对原生 html 的非官方 attribute 设置 false 值。
<!-- Vue 3 会解析为 <a disabled="false">链接</a> 其实还是 disabled 了... -->
<a :disabled="!!isDisabled">链接</a>
<!-- Vue 3 需要改变写法 -->
<a :disabled="isDisabled ? true : null">链接</a>
<!-- 或者 a 标签暂时先替换为 Link 组件 -->
<Link :disabled="!!isDisabled">链接</Link>
$ 开头的响应式属性失效
问题:Vue 3 为了防止内部属性冲突,直接不再对$开头的变量进行响应式代理,甚至直接读不到值。
解决:重命名,避免$ _开头的响应式属性命名。
data() {
return {
validName: 'validName',
// this.$instance 读不到,始终为 undefined,需要更换名称为 instance
$instance: new instance()
}
}
部分三方依赖库实例响应式问题
问题:选项式写法中,给三方依赖实例响应式赋值时,会导致依赖自身功能实现出问题。
解决:用 markRaw 标记为不需要响应式代理。
import { markRaw } from 'vue';
data() {
return {
codemirror: null
}
},
mounted() {
this.codemirror = markRaw(CodeMirror.fromTextArea(this.$refs.textarea, cmOptions))
}
extends 不会继承 setup 函数
问题:父组件 extends 子组件的时候,如果子组件里有 setup 函数,父组件不会继承。
解决:不要混用组合式和选项式写法,以后尽量用组合式写法吧!
heywhale-ui
<!-- Page 组件的 current props 需要替换为 v-model -->
<Page :current=""></Page>
<Page v-model=""></Page>
重构 todo list 快速核对
- 可以提前做的
- 替换过滤器
filters - 移除
functional - 替换事件总线
new Vue()->mitt - 替换状态管理
Vuex->Pinia 2.0
- 替换过滤器
- 起步
- 新模板文件结构
- 依赖包升级 Vue 3 版本
- 全局 API 变化
npm run lint
- 模板指令
v-model变化<template v-for>的 key 设置在<template>标签上- 移除
v-on.native
- 组件
- Vue 异步组件
defineAsyncComponent - 声明
emits(持续性工作)
- Vue 异步组件
- 渲染函数
- 渲染函数全局导入
import { h } from 'vue' - VNode Prop 扁平化
this.$scopedSlots.xxx->this.$slots.xxx()- 移除
$listeners - 检查
inheritAttrs: false
- 渲染函数全局导入
- 移除 APIs
keyCodes$on$off$oncepropsData$nextTick$set$delete以及相关全局 API
- 其它
- attribute 行为变化
directiveAPI 变化- 过渡类名变化
- 生命周期钩子变化
- watch 数组行为变化
- KeepAlive 下仅允许一个子元素
- 检查
$_开头响应式变量命名 - 检查三方依赖库实例
- 组合式代码重构(持续性工作)