vue3 升级实战笔记

最近要将公司项目的移动端进行 vue3 的升级工作,就顺便记录下升级过程。

项目迁移的思路

我的想法是最小改动原则。

  • 从 vue2.x 升级到 vue3,且使用 vue3 的 选项式 API
  • 构建工具要从 vue-cli(webpack)升级到 vite。
  • 路由需要升级到最新的 vue-router.
  • 状态管理器可以使用最新的 vuex,后续迁移到 pinia.
  • 组件库也需要升级到 vue3 的版本。
  • 网络请求依旧可以用 axios。

项目创建

由于改动太大,我并没有在原项目上进行升级,而是使用最新的 vue 模板来新建项目,然后逐步迁移代码。

$ npm init vue@latest
✔ Project name: … app-v3
✔ Add TypeScript? … No
✔ Add JSX Support? … Yes
✔ Add Vue Router for Single Page Application development? … Yes
✔ Add Pinia for state management? … No
✔ Add Vitest for Unit testing? … No
✔ Add Cypress for both Unit and End-to-End testing? … No
✔ Add ESLint for code quality? … Yes
✔ Add Prettier for code formatting? … Yes

Scaffolding project in ./<your-project-name>...
Done.

这里我并没有用 TS 和 Pinia 库,主要还是因为用了这两个库,迁移成本会大大增加,需要改动的代码会多很多。以后再慢慢升级吧。

安装依赖

项目也运行了一两年了,用到的依赖必然是不少的。逐个进行安装。这里需要将库分为两类:

vue 相关库

这类库要么是基于 vue3 来重写的,要么就是针对 vue3 的新特性而设计实现的。这类库就需要从 vue2 升级到 vue3。我项目中用到的库有:

{
  "element-plus": "^2.3.2",
  "vant": "^4.1.2",
  "vue": "^3.2.47",
  "vue-router": "4",
  "vuex": "^4.0.2",
  "vxe-table": "^4.3.11"
}

对于这类库,或多或少会和老版本的 API 有一些出入,所幸一般优秀第三方库的文档都会提供 vue3 的迁移指南。

其他工具库

这类库基本上是可以直接从 package.json 里面复制过来用的。后续执行 npm install 安装即可。

{
  "@antv/g2plot": "^2.4.29",
  "axios": "^1.3.4",
  "dayjs": "^1.11.7",
  "lodash": "^4.17.21",
  "numeral": "^2.0.6",
  "query-string": "^8.1.0",
  "vconsole": "^3.15.0",
  "xe-utils": "^3.5.7"
}

dev 开发库

另外,在开发中还会用到一些开发工具库,如 CSS 预处理器

> npm add -D sass

这类开发相关库的用法参考 vite 官方指引(感觉它的文档和 vue-cli 还是有些类似的)。

注册依赖库

这些其实就很简单,按照各自官方文档配置即可。一般都是 app.use(lib, { ...options }) 的写法。

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import Vant from 'vant'
import 'vant/lib/index.css'
import VXETable from 'vxe-table'
import 'vxe-table/lib/style.css'

const app = createApp(App)

app.use(router)
app.use(store)
app.use(ElementPlus)
app.use(Vant)
app.use(VXETable)

app.mount('#app')

接口代理

代理是开发阶段前后端联调的关键,比如第一时间安排上。

// vite.config.js
export default defineConfig({
  ...
  server: {
    port: 7001,
    proxy: {
      '/api': 'http://101.44.97.172',
    },
  },
})

代码如何迁移

由于并没有使用 TypeScript 和 Pinia,所以完全可以一股脑将项目全部移到新项目上。再对改动逐个调整。

处理 devtools 不显示的问题

在跑 vue3 项目的时候,发现它并没有将 vue-devtools 调试工具开起来,于是就去官网查询。

https://devtools.vuejs.org/guide/faq.html#the-vue-devtools-don-t-show-up

解决方案是修改一个环境变量 __VUE_PROD_DEVTOOLS__,它默认是 false,需要改为 true 来打开。

__VUE_PROD_DEVTOOLS__ (enable/disable devtools support in production, default: false)

对于 vite 构建的项目(一般都是用的 vite),可以使用使用 define 选项.

// vite.config.js
export default defineConfig({
  ...
  define: {
    __VUE_PROD_DEVTOOLS__: true,
  },
})

vue-router

在路由方面,改动并不大(毕竟是同一个库的升级版)。下面列出了 vue2 和 vue3 的使用方式不同之处。

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const router = new VueRouter({
  routes: [
    {
      path: '/',
      name: 'welcome',
      component: () => import('@/views/Welcome/index.vue'),
      meta: {
        title: '引导页',
        key: 'welocome',
      },
    },
  ],
})

window.vm = new Vue({
  router,
  render: (h) => h(App),
}).$mount('#app')
import { createApp } from 'vue'
import { createRouter, createWebHashHistory } from 'vue-router'

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    {
      path: '/',
      name: 'welcome',
      component: Welcome,
      meta: {
        title: '引导页',
        key: 'welocome',
      },
    },
  ],
})

const app = createApp(App)
app.use(router)

另外一点不同是在 JavaScript 中去 route 的方式不同。

在 vue2 中可以在 vue 实例中拿到路由信息。

const $route = window.vm.$route

而在 vue3 中我是通过如下方式取的 route 信息。

import router from '@/router'

const $route = router.currentRoute.value // currentRoute 是一个 ref() 对象

目前用到的就这些,其他改动详见 从 Vue2 迁移 | Vue Router

vuex

关于 vuex 部分,表现倒是出奇的好。代码拷贝过来后修改了安装过程,其他都能运行正常。

import { createStore } from 'vuex'

export const store = createStore({
  state() {
    return {
      count: 1,
    }
  },
})
import { createApp } from 'vue'
import { store } from './store'
import App from './App.vue'

const app = createApp(App)

app.use(store)

app.mount('#app')

这就体现出我之前所说的 vuex 比 pinia 的迁移上的好处了。

vue3 语法修改

由于采用了选项式语法来写 vue ,所以老项目的大多数 API 还是可以适用的。最需要关注变化是那些非兼容性改变 | Vue 3 迁移指南。下面列举一些我遇到的问题。

  • v-deep 改为 :deep()
  • v-model 的定义名称改变:value 变为 modelValueinput 事件变为 update:modelValue
  • :visible.sync="" 变为 v-model:visible=""
  • 组件的 v-model 变为了参数绑定 v-model:value
export default {
  props: {
    value: String,
  },
  emits: ['update:value'],
  methods: {
    handleClick() {
      const index = this.options.findIndex(
        (option) => option.value === this.value,
      )
      if (index === this.options.length - 1) {
        this.$emit('update:value', this.options[0].value)
      } else {
        this.$emit('update:value', this.options[index + 1].value)
      }
    },
  },
}

vant 组件库的变化

我的移动端项目用到了大量 vant 的组件库,所以记录了一下影响较大的改动。

  • DatetimePicker 组件被拆分成了三个子组件,我所用到的是 datePicker 的日期选择器,它的 v-model 值从之前的 Date() 类数据变成了字符串数组 ['2022', '09']
  • datePicker 月份选择器不再是通过 type 来决定,而是直接定义选择器列的属性 :columns-type="['year', 'month']"
  • toast 提示信息从 Toast() 函数变为了 showToast() 函数。
  • popup 的 visible.sync="" 变为了 v-model:visible=""
  • tab 的 v-model="" 变为了 v-model:active=""
  • calender 的 v-model="" 变为了 v-model:show=""

具体还是可以参考 vant 的 升级指南 来进行更新。

总结

  • 保证最小改动原则的去升级到 vue3 是最安全快速的。
  • 在升级的时候,一定要提前多看看相关升级指南,比自己琢磨要好很多。可以省不少时间。
  • 由于 vue 的升级,组件库都会有一些变化。所以对于第三方组件,不仅要按照升级指南逐步升级,还要多多测试交互逻辑。这块改动挺大的。
  • vue3 语法中,尤其注意 v-model 变化对组件库的影响,我在修改组件库问题时遇到最多的就是这个。
  • 如果对组件库通过元素选择器 querySelector() 做过一些渗透性的改动,需要重新检查。因为这类不体现在文档中的改动随着版本的升级有些许变化是正常且合理的。
const elements = document.getElementsByClassName('vxe-table--body-wrapper')
elements.addEventListener('touchend', () => {})

// 这种结构性的元素获取最容易出问题
document.querySelector('#app > div > div:nth-child(3)')
.header-tabs {
  width: 100%;

  :deep(.van-tab) {
    font-size: 16px;
    font-family: PingFang SC;
    font-weight: 500;
    color: #282c32;
  }

  :deep(.van-tab--active) {
    font-size: 16px;
    font-family: PingFang SC;
    font-weight: bold;
    color: #f6674f;
  }

  :deep(.van-tabs__line) {
    width: 65px;
    background: #f6674f;
  }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,718评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,683评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,207评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,755评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,862评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,050评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,136评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,882评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,330评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,651评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,789评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,477评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,135评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,864评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,099评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,598评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,697评论 2 351

推荐阅读更多精彩内容