随着 vue3 的发布和越来越多项目的使用,之前使用 vue2 的项目也不能落下。虽然 vue3 具有一定的向下兼容性,但还是有一些破坏性的改动,并且 vue3 相较于 vue2 在运行效率和开发体验上有较好的提升。vue3 比较明显的一个变化就是添加了 setup(){}
函数,使得业务逻辑的复用性更强,代码组织更具有条理性。即使是这样,小改动还是很多的。
在大佬们的指导下,整理了目前 vue2 升级为 vue3 的不兼容变更项。如有遗漏,望大家不吝指出。
vue2 升级 vue3
- 升级前
- 模版
- 渲染函数
- 其他改动
- 移除 API
- 升级中
- 全局
- 模版
- 组件
- 渲染函数
- 生命周期
- 其他
- 升级后
- 相关配套设施
- elementUI
- vuex
- vue-router
- 创建实例
- 路由模式
- 挂载根实例
- 使用
- break changes
- 测试
升级前
在正式升级前,可以提前完成兼容性的改动。
模版
- 排查同时使用
v-if
和v-for
的元素,避免在同一个元素上同时使用,可以通过computed
方式过滤出可见元素的列表; - 排查元素
v-bind
的前后使用,确保v-bind
先定义,再定义各个属性; - 排查
v-for
中使用ref
的地方,将ref
绑定为一个函数;
渲染函数
- 排查所有
this.$scopedSlots
更改为this.$slots
; - 全局搜索使用
slot-scope
的地方改为v-slot
;
其他改动
- 排查所有的组件中的
data
类型,确保data
必须是返回object
的function
; - 排查所有使用
mixin
或extend
的组件,确保data
中的属性不重复,或者都为顶级属性; - 排查所有的
watch
的参数,如果监听参数为数组,需要设置deep: true
;
移除 API
- 排查使用数字 (即键码) 作为
v-on
的修饰符,更改为别名的方式 参照。示例:
vue2
v-on:keyup.112
vue3
v-on:keyup.delete
- 移除
config.keyCodes
; - 排查使用
keyCode
,建议转换为对应的kebab-cased
(短横线) 命名 参照; - 全局搜索
filters
,更改为使用computed
或function
代替filters
;对于使用较多场景的filters
可以考虑使用全局的filters
示例:
// main.js
const app = createApp(App)
app.config.globalProperties.$filters = {
currencyUSD(value) {
return '$' + value
}
}
// vue组件
<template>
<h1>Bank Account Balance</h1>
<p>{{ $filters.currencyUSD(accountBalance) }}</p>
</template>
- 全局搜索
inline-template
,移除inline-template
标识,如果必须使用可用<script>
或者默认Slot
; - 全局搜索
$children
,移除$children
实例,如果需要访问子组件实例可用$refs
; - 全局搜索
$destroy
,移除$destroy
实例,不应该手动管理单个Vue
组件的生命周期;
升级中
全局
- 排查
vue
实例创建方式,将new Vue()
更改为createApp
;
2.x Global API | 3.x Instance API (app) |
Vue.config | app.config |
Vue.config.productionTip | removed ( see link ) |
Vue.config.ignoredElements | app.config.isCustomElement ( see link ) |
Vue.component | app.component |
Vue.directive | app.directive |
Vue.mixin | app.mixin |
Vue.use | app.use ( see link ) |
- 排查使用的全局
API
更改为ES
模块;
- Vue.nextTick
- Vue.observable(更改为Vue.reactive)
- Vue.version
- Vue.h
- Vue.compile(仅完整版本)
- Vue.set(仅在兼容版本中)
- Vue.delete(仅在兼容版本中)
模版
- 排查没有修饰符的
v-model
,分别将prop
和event
命名更改为modelValue
和update:modelValue
; - 全局搜索
.native
,移除v-on
的.native
修饰符,将需要进行参数校验的emit
写入emits
中; - 移除没有指令的
<template>
,vue3 支持多个节点返回; - 全局搜索
.sync
,将元素中v-model.sync
更改为v-model:value
;
组件
- 排查函数式组件,移除配置中
{ functional: true }
和模板中<template functional>
的functional
; - 排查单文件组件,
props
重命名为$props
,attrs
重命名为$attrs
; - 排查路由和异步组件,异步组件通过
defineAsyncComponent
方法创建; - 排查
defineAsyncComponent
,defineAsyncComponent
中component
选项需要改成loader
,同时loader
函数移除了resolve
和reject
参数,必须手动返回Promise
;
渲染函数
- 排查所有使用
render
的组件,更改VNode domProps
结构 参照; - 全局搜索
$listeners
,删除所有的$listeners
; - 排查所有设置了
{ inheritAttrs: false }
的组件,确保升级后的样式是否正确。如果之前依赖class
和style
。vue3 中$attrs
包含了所有的attribute
包括class
和style
,这些attribute
vue2 版本中class
和style
则不会; - 全局搜索
v-enter
替换为v-enter-from
,类名重命名; - 全局搜索
v-leave
替换为v-leave-from
,类名重命名; - 排查
watch
和$watch
,watch
不再支持点分隔字符串路径。如user.userName
可以将监听的参数更改为computed
; - 排查使用到
outerHTML
的组件,在 vue2 中,应用根容器的outerHTML
将替换为根组件模板 (如果根组件没有模板/渲染选项,则最终编译为模板)。vue3 现在使用应用程序容器的innerHTML
,容器本身不再被视为模板的一部分;
生命周期
vue2 | vue3 | vue3 setup |
beforeCreate | beforeCreate | setup() 内部 |
created | created | setup() 内部 |
beforeMount | beforeMount | onBeforeMount |
mounted | mounted | onMounted |
beforeUpdate | beforeUpdate | onBeforeUpdate |
updated | updated | onUpdated |
|
| onBeforeUnmount |
|
| onUnmounted |
errorCaptured | errorCaptured | onErrorCaptured |
renderTracked | onRenderTracked | |
renderTriggered | onRenderTriggered |
其他
- 排查全部
prop
的default
,确保不含this
,如有需要可以用inject
来访问注入的property
; - 查找自定义指令(通常在
directive
文件夹下),修改生命周期如下:
vue2 | vue3 |
bind | beforeMount |
inserted | mounted |
beforeUpdate | |
update | 移除(改用 updated ) |
componentUpdated | updated |
beforeUnmount | |
unbind | unmounted |
升级后
- 逐步移除
option API
替换为composition API
; - 对于
JS
的开发可以考虑迁移为TS
;
相关配套设施
elementUI
目前还不支持 vue3;
vuex
已支持 vue3 ,目前改动不大,任务紧急度较低;
vue-router
创建实例
将 new VueRouter
更改为 VueRouter.createRouter
路由模式
查找路由下的 { mode: 'hash' }
,更改为 { history: VueRouter.createWebHashHistory() }
挂载根实例
通过 { app.use }
的方式挂载路由
使用
在 option API
中依旧可以通过 this.$route
读取到当前路由信息,this.$router
读取到路由表信息;
在 composition API
中需要使用 useRouter
和 useRoute
函数。例如:
const router = useRouter();
const route = useRoute();
break changes
移除 tag
新增 v-slot
例如:
<router-link to="/about"
custom
v-slot="{ href, route, navigate, isActive, isExactActive }"
>
<NavLink :active="isActive" :href="href" @click="navigate">
{{ route.fullPath }}
</NavLink>
</router-link>
v-slot
的对象包含下面几个属性:
-
href
:解析后的URL
。将会作为一个a
元素的href attribute
; -
route
:解析后的规范化的地址; -
navigate
:触发导航的函数。会在必要时自动阻止事件,和router-link
同理; -
isActive
:如果需要应用激活的class
则为true
。允许应用一个任意的class
; -
isExactActive
:如果需要应用精确激活的class
则为true
。允许应用一个任意的class
;
使用
useLink
和v-slot
API
相同,返回的都是相同的属性。
测试
项目构建成功,通过页面切换,验证功能是否按照预期显示。