随着 vue3 的发布和越来越多项目的使用,之前使用 vue2 的项目也不能落下。虽然 vue3 具有一定的向下兼容性,但还是有一些破坏性的改动,并且 vue3 相较于 vue2 在运行效率和开发体验上有较好的提升。vue3 比较明显的一个变化就是添加了 setup(){} 函数,使得业务逻辑的复用性更强,代码组织更具有条理性。即使是这样,小改动还是很多的。

   在大佬们的指导下,整理了目前 vue2 升级为 vue3 的不兼容变更项。如有遗漏,望大家不吝指出。


vue2 升级 vue3

  • 升级前
  • 模版
  • 渲染函数
  • 其他改动
  • 移除 API
  • 升级中
  • 全局
  • 模版
  • 组件
  • 渲染函数
  • 生命周期
  • 其他
  • 升级后
  • 相关配套设施
  • elementUI
  • vuex
  • vue-router
  • 创建实例
  • 路由模式
  • 挂载根实例
  • 使用
  • break changes
  • 测试


升级前

在正式升级前,可以提前完成兼容性的改动。

模版

  1. 排查同时使用 v-ifv-for 的元素,避免在同一个元素上同时使用,可以通过 computed 方式过滤出可见元素的列表;
  2. 排查元素 v-bind 的前后使用,确保 v-bind 先定义,再定义各个属性;
  3. 排查 v-for 中使用 ref 的地方,将 ref 绑定为一个函数;

渲染函数

  1. 排查所有 this.$scopedSlots 更改为 this.$slots
  2. 全局搜索使用 slot-scope 的地方改为 v-slot ;

其他改动

  1. 排查所有的组件中的 data 类型,确保 data 必须是返回 objectfunction
  2. 排查所有使用 mixinextend 的组件,确保 data 中的属性不重复,或者都为顶级属性;
  3. 排查所有的 watch 的参数,如果监听参数为数组,需要设置 deep: true

移除 API

  1. 排查使用数字 (即键码) 作为 v-on 的修饰符,更改为别名的方式 参照。示例:
vue2
v-on:keyup.112

vue3
v-on:keyup.delete
  1. 移除 config.keyCodes
  2. 排查使用 keyCode ,建议转换为对应的 kebab-cased (短横线) 命名 参照
  3. 全局搜索 filters ,更改为使用 computedfunction 代替 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>
  1. 全局搜索 inline-template ,移除 inline-template 标识,如果必须使用可用 <script> 或者默认 Slot
  2. 全局搜索 $children ,移除 $children 实例,如果需要访问子组件实例可用 $refs
  3. 全局搜索 $destroy ,移除 $destroy 实例,不应该手动管理单个 Vue 组件的生命周期;

升级中

全局

  1. 排查 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 )

  1. 排查使用的全局 API 更改为 ES 模块;
  • Vue.nextTick
  • Vue.observable(更改为Vue.reactive)
  • Vue.version
  • Vue.h
  • Vue.compile(仅完整版本)
  • Vue.set(仅在兼容版本中)
  • Vue.delete(仅在兼容版本中)

模版

  1. 排查没有修饰符的 v-model,分别将 propevent 命名更改为 modelValueupdate:modelValue
  2. 全局搜索.native,移除 v-on.native 修饰符,将需要进行参数校验的 emit 写入 emits 中;
  3. 移除没有指令的 <template>,vue3 支持多个节点返回;
  4. 全局搜索 .sync,将元素中 v-model.sync 更改为 v-model:value

组件

  1. 排查函数式组件,移除配置中 { functional: true } 和模板中 <template functional>functional
  2. 排查单文件组件,props 重命名为 $propsattrs 重命名为 $attrs
  3. 排查路由和异步组件,异步组件通过 defineAsyncComponent 方法创建;
  4. 排查 defineAsyncComponentdefineAsyncComponentcomponent 选项需要改成 loader ,同时 loader 函数移除了 resolvereject 参数,必须手动返回 Promise

渲染函数

  1. 排查所有使用 render 的组件,更改 VNode domProps 结构 参照
  2. 全局搜索 $listeners ,删除所有的 $listeners
  3. 排查所有设置了 { inheritAttrs: false } 的组件,确保升级后的样式是否正确。如果之前依赖 classstyle 。vue3 中 $attrs 包含了所有的 attribute 包括 classstyle ,这些 attribute vue2 版本中 classstyle 则不会;
  4. 全局搜索 v-enter 替换为 v-enter-from ,类名重命名;
  5. 全局搜索 v-leave 替换为 v-leave-from ,类名重命名;
  6. 排查 watch$watchwatch 不再支持点分隔字符串路径。如 user.userName 可以将监听的参数更改为 computed
  7. 排查使用到 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

beforeDestroy

beforeUnmount

onBeforeUnmount

destroyed

unmounted

onUnmounted

errorCaptured

errorCaptured

onErrorCaptured

renderTracked

onRenderTracked

renderTriggered

onRenderTriggered

其他

  1. 排查全部 propdefault ,确保不含 this ,如有需要可以用 inject 来访问注入的 property
  2. 查找自定义指令(通常在 directive 文件夹下),修改生命周期如下:

vue2

vue3

bind

beforeMount

inserted

mounted

beforeUpdate

update

移除(改用 updated )

componentUpdated

updated

beforeUnmount

unbind

unmounted

升级后

vue3 官网

  1. 逐步移除 option API 替换为 composition API
  2. 对于 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 中需要使用 useRouteruseRoute 函数。例如:

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 的对象包含下面几个属性:

  1. href:解析后的 URL。将会作为一个 a 元素的 href attribute
  2. route:解析后的规范化的地址;
  3. navigate:触发导航的函数。会在必要时自动阻止事件,和 router-link 同理;
  4. isActive:如果需要应用激活的 class 则为 true。允许应用一个任意的 class
  5. isExactActive:如果需要应用精确激活的 class 则为 true。允许应用一个任意的 class

使用 useLinkv-slot API 相同,返回的都是相同的属性。

测试

项目构建成功,通过页面切换,验证功能是否按照预期显示。