糯麦 NurMai

400-158-5662

糯麦科技

/

新闻资讯

/

技术讨论

/

你升级 Vue3了吗?

你升级 Vue3了吗?

原创 新闻资讯

于 2023-09-22 10:56:26 发布

17425 浏览

根据 Vue 官方文档的说明,Vue 2.x 的生命周期已经结束,这意味着从明年开始:Vue 2.x 将不再得到更新和升级,不会新增任何特性,也不会再修复任何缺陷。


可以继续问我:你了解 Vue3 的哪些新特性?能分享一些 Vue3 相比 Vue2 的改进吗?哪些业务领域在使用 Vue2?虽然 Vue3 已经发布近三年,但据我所知,目前仍有许多业务领域正在使用 Vue2,尚未升级到 Vue3。


为什么要等到 Vue2 彻底停止维护,才考虑升级 Vue3 这个如此重要的问题呢?

本文是一篇 Vue2 升级 Vue3 的指南,主要包含以下部分:

1. 使用 Vue CLI 搭建 Vue2 工程

2. 使用 ElementUI 搭建表格、表单

3. 使用 OpenTiny Vue 替换一个组件

4. 使用 OpenTiny Vue 替换一个页面

5. 使用 OpenTiny Vue 替换整个应用

6. 使用 gogocode 升级到 Vue3,组件代码无需修改


1. 创建 Vue2 项目

先用 Vue CLI 创建一个 Vue2 项目(也可以使用 Vite 配合 @vitejs/plugin-vue2 或 vite-plugin-vue2 插件)。

// 安装 Vue CLI
npm install -g @vue/cli

// 创建 Vue2 项目
vue create vue2-demo

输出以下信息说明项目创建成功

🎉  Successfully created project vue2-demo.
👉  Get started with the following commands:

$ cd vue2-demo
$ yarn serve

创建好之后可以执行以下命令启动项目

yarn serve

输出以下命令说明启动成功

App running at:
- Local:   http://localhost:8080/ 
- Network: http://192.168.1.102:8080/

效果如下


1.jpg


2. 使用 ElementUI 搭建表格、表单

安装 VueRouter

npm i vue-router@3

main.js

import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'

const router = new VueRouter({
  routes: [
    {
      path: '/',
      component: () => import('./components/HomePage.vue')
    },
    {
      path: '/form',
      component: () => import('./components/FormPage.vue')
    },
    {
      path: '/list',
      component: () => import('./components/ListPage.vue')
    }
  ]
})

Vue.config.productionTip = false
Vue.use(VueRouter)

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

App.vue

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">

    <p>
      <!-- use the router-link component for navigation. -->
      <!-- specify the link by passing the `to` prop. -->
      <!-- `<router-link>` will render an `<a>` tag with the correct `href` attribute -->
      <router-link to="/">Home</router-link>
      <router-link to="/form">Form</router-link>
      <router-link to="/list">List</router-link>
    </p>
    <!-- route outlet -->
    <!-- component matched by the route will render here -->
    <router-view></router-view>
  </div>
</template>

安装 ElementUI

npm i element-ui

在 src/views/FormPage.vue 中使用 ElementUI 组件,从 ElementUI 官网组件 demo 里面拷贝代码即可。


典型表单:

https://element.eleme.io/#/zh-CN/component/form#dian-xing-biao-dan
<template>
<el-form ref="form" :model="form" label-width="80px">
  <el-form-item label="活动名称">
    <el-input v-model="form.name"></el-input>
  </el-form-item>
  <el-form-item label="活动区域">
    <el-select v-model="form.region" placeholder="请选择活动区域">
      <el-option label="区域一" value="shanghai"></el-option>
      <el-option label="区域二" value="beijing"></el-option>
    </el-select>
  </el-form-item>
  <el-form-item label="活动时间">
    <el-col :span="11">
      <el-date-picker type="date" placeholder="选择日期" v-model="form.date1" style="width: 100%;"></el-date-picker>
    </el-col>
    <el-col class="line" :span="2">-</el-col>
    <el-col :span="11">
      <el-time-picker placeholder="选择时间" v-model="form.date2" style="width: 100%;"></el-time-picker>
    </el-col>
  </el-form-item>
  <el-form-item label="即时配送">
    <el-switch v-model="form.delivery"></el-switch>
  </el-form-item>
  <el-form-item label="活动性质">
    <el-checkbox-group v-model="form.type">
      <el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
      <el-checkbox label="地推活动" name="type"></el-checkbox>
      <el-checkbox label="线下主题活动" name="type"></el-checkbox>
      <el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
    </el-checkbox-group>
  </el-form-item>
  <el-form-item label="特殊资源">
    <el-radio-group v-model="form.resource">
      <el-radio label="线上品牌商赞助"></el-radio>
      <el-radio label="线下场地免费"></el-radio>
    </el-radio-group>
  </el-form-item>
  <el-form-item label="活动形式">
    <el-input type="textarea" v-model="form.desc"></el-input>
  </el-form-item>
  <el-form-item>
    <el-button type="primary" @click="onSubmit">立即创建</el-button>
    <el-button>取消</el-button>
  </el-form-item>
</el-form>
</template>
<script>
  export default {
    data() {
      return {
        form: {
          name: '',
          region: '',
          date1: '',
          date2: '',
          delivery: false,
          type: [],
          resource: '',
          desc: ''
        }
      }
    },
    methods: {
      onSubmit() {
        console.log('submit!');
      }
    }
  }
</script>

效果如下

2.jpg

表格页面也一样。

src/views/ListPage.vue

<template>
  <div>
    <div class="filter-bar">
      <el-select v-model="value" placeholder="请选择">
        <el-option
          v-for="item in options"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        >
        </el-option>
      </el-select>
      <el-date-picker v-model="value1" type="daterange"> </el-date-picker>
      <el-input
        v-model="search"
        placeholder="输入关键字搜索"
        style="width: 300px"
      />
      <el-button>搜索</el-button>
    </div>
    <el-table :data="tableData" style="width: 100%">
      <el-table-column prop="date" label="日期" width="180"> </el-table-column>
      <el-table-column prop="name" label="姓名" width="180"> </el-table-column>
      <el-table-column prop="address" label="地址"> </el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      value1: '',
      options: [
        {
          value: '选项1',
          label: '王小虎'
        },
        {
          value: '选项2',
          label: '张三'
        },
        {
          value: '选项3',
          label: '李小萌'
        },
        {
          value: '选项4',
          label: '令狐冲'
        }
      ],
      value: '',
      search: '',
      tableData: [
        {
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        },
        {
          date: '2016-05-04',
          name: '张三',
          address: '上海市普陀区金沙江路 1517 弄'
        },
        {
          date: '2016-05-01',
          name: '李小萌',
          address: '上海市普陀区金沙江路 1519 弄'
        },
        {
          date: '2016-05-03',
          name: '令狐冲',
          address: '上海市普陀区金沙江路 1516 弄'
        }
      ]
    }
  }
}
</script>

<style lang="less" scoped>
.filter-bar {
  display: flex;

  & > * {
    margin-right: 20px;
  }
}
</style>

效果如下

3.jpg

首页可以放一张轮播图。

src/views/HomePage.vue

<template>
  <el-carousel>
    <el-carousel-item v-for="item in 4" :key="item">
      <img :src="`https://picsum.photos/1350/900?random=${item}`" style="width: 100%;">
    </el-carousel-item>
  </el-carousel>
</template>

<style>
  .el-carousel__item h3 {
    color: #475669;
    font-size: 14px;
    opacity: 0.75;
    line-height: 150px;
    margin: 0;
  }

  .el-carousel__item:nth-child(2n) {
     background-color: #99a9bf;
  }
  
  .el-carousel__item:nth-child(2n+1) {
     background-color: #d3dce6;
  }
</style>

效果如下

4.jpg

参考:

表单:https://element.eleme.io/#/zh-CN/component/form

表格:https://element.eleme.io/#/zh-CN/component/table

轮播:

https://element.eleme.io/#/zh-CN/component/carousel


3. 使用 OpenTiny Vue 替换一个组件

OpenTiny Vue 的组件都是支持按需引入的,一开始我们步子不要迈得太大,先尝试替换一个 Button 组件。

安装 @opentiny/vue@2

npm i @opentiny/vue@2


5.jpg


表单页面里面有两个按钮,我们尝试将其替换成 OpenTiny Vue 的 Button 组件。

替换的步骤很简单,不需要修改现有的代码,只需要增加4行代码即可。

src/views/FormPage.vue

<template>
<el-form ref="form" :model="form" label-width="80px">
  <el-form-item label="活动名称">
    <el-input v-model="form.name"></el-input>
  </el-form-item>
  ...
  <el-form-item>
    <el-button type="primary" @click="onSubmit">立即创建</el-button>
    <el-button>取消</el-button>
  </el-form-item>
</el-form>
</template>
<script>
+  import { Button } from '@opentiny/vue'

  export default {
+    components: {
+      ElButton: Button
+    },
    data() {
      return {
        form: {
          name: '',
          ...
        }
      }
    },
    methods: {
      onSubmit() {
        console.log('submit!');
      }
    }
  }
</script>

效果如下

6.jpg


4. 使用 OpenTiny Vue 替换一个页面

接下来我们步子逐渐迈大一点,将整个 FormPage 页面的 ElementUI 组件全部替换成 OpenTiny Vue 的组件。

FormPage 页面一共有以下组件:

Button

Form

FormItem

Input

Select

Option

Col

DatePicker

TimePicker

Switch

CheckboxGroup

Checkbox

RadioGroup

Radio

替换的方式和前面替换 Button 组件一模一样,只需要多加一些组件。

<template>
<el-form ref="form" :model="form" label-width="80px">
  <el-form-item label="活动名称">
    <el-input v-model="form.name"></el-input>
  </el-form-item>
  ...
  <el-form-item>
    <el-button type="primary" @click="onSubmit">立即创建</el-button>
    <el-button>取消</el-button>
  </el-form-item>
</el-form>
</template>
<script>
  import {
    Button,
+    Form,
+    FormItem,
+    Input,
+    Select,
+    Option,
+    Col,
+    DatePicker,
+    TimePicker,
+    Switch,
+    CheckboxGroup,
+    Checkbox,
+    RadioGroup,
+    Radio,
  } from '@opentiny/vue'

  export default {
    components: {
      ElButton: Button,
+      ElForm: Form,
+      ElFormItem: FormItem,
+      ElInput: Input,
+      ElSelect: Select,
+      ElOption: Option,
+      ElCol: Col,
+      ElDatePicker: DatePicker,
+      ElTimePicker: TimePicker,
+      ElSwitch: Switch,
+      ElCheckboxGroup: CheckboxGroup,
+      ElCheckbox: Checkbox,
+      ElRadioGroup: RadioGroup,
+      ElRadio: Radio,
    },
    data() {
      return {
        form: {
          name: '',
          ...
        }
      }
    },
    methods: {
      onSubmit() {
        console.log('submit!');
      }
    }
  }
</script>

效果如下

7.jpg


5. 使用 OpenTiny Vue 替换整体应用

最后一步就是使用 OpenTiny Vue 替换整个应用的 ElementUI。

我们可以用前面的方法进行替换,但考虑到整个应用的页面众多,我们采取另一种方式。

我们已经全局注册了 ElementUI 组件库,接下来我们全局注册 OpenTiny Vue 组件库。

import Vue from 'vue'
- import ElementUI from 'element-ui'
- import 'element-ui/lib/theme-chalk/index.css'
+ import TinyVue from '@opentiny/vue'
import App from './App.vue'
import VueRouter from 'vue-router'

- Vue.use(ElementUI)
+ Vue.use(TinyVue)

const router = new VueRouter({
  routes: [
    ...
  ]
})

Vue.config.productionTip = false
Vue.use(VueRouter)

new Vue({
  router,
  render: (h) => h(App)
}).$mount('#app')

然后全局替换 el- 为 tiny-,一步到位!


8.jpg


效果如下

首页轮播

9.jpg

表单

10.jpg

表格

11.jpg

是不是非常丝滑,更丝滑的还在后面!

接下来我们将借助一款神器:gogocode,实现 Vue2 项目平滑升级 Vue3。


6. 使用 gogocode 升级到 Vue3

安装 gogocode:

npm install gogocode-cli -g

转换源码:

gogocode -s ./src/ -t gogocode-plugin-vue -o ./src/

升级依赖:

gogocode -s package.json -t gogocode-plugin-vue -o package.json

升级 TinyVue 组件库到 3.0 版本

npm i @opentiny/vue@3

组件代码无需做任何修改,完成 Vue2 项目平滑升级到 Vue3 

执行 npm run dev 命令启动项目,除了 Vue 版本号变化之后,其他任何效果都没有变化。

首页轮播

1.jpg

表单

2.jpg

表格

3.jpg

遇到的问题

问题一:error 'v-model' directives require no argument vue/no-v-model-argument

解决方法:修改 FormPage.vue 中的 v-model:value 为 v-model 即可

问题二:Failed to resolve component: router-link

解决方案:修改 main.js 中 use(router) 代码顺序即可

window.$vueApp = Vue.createApp(App)

window.$vueApp.mount('#app')
import * as Vue from 'vue'
import TinyVue from '@opentiny/vue'
import App from './App.vue'
import * as VueRouter from 'vue-router'

- window.$vueApp.use(TinyVue)

const router = VueRouter.createRouter({
  history: VueRouter.createWebHashHistory(),
  routes: [
    ...
  ],
})

window.$vueApp = Vue.createApp(App)
+ window.$vueApp.use(TinyVue)
+ window.$vueApp.use(router) // 这一行代码需要放到 mount 之前
window.$vueApp.mount('#app')
window.$vueApp.config.globalProperties.routerAppend = (path, pathToAppend) => {
  return path + (path.endsWith('/') ? '' : '/') + pathToAppend
}

- window.$vueApp.use(router)


如果你在升级 Vue3 的过程中遇到任何问题,欢迎在评论区进行讨论,也欢迎添加 OpenTiny 小助手 opentiny-official 与我们交流!

本文涉及到的源码链接:

https://github.com/opentiny/cross-framework-component

Element 升级 OpenTiny 的 demo 项目在 packages/element-to-opentiny 子包里。

vue2 项目在 vue2 分支

vue3 项目在 vue3 分支


关于 OpenTiny

OpenTiny 是一套华为云出品的企业级组件库解决方案,适配 PC 端 / 移动端等多端,涵盖 Vue2 / Vue3 / Angular 多技术栈,拥有主题配置系统 / 中后台模板 / CLI 命令行等效率提升工具,可帮助开发者高效开发 Web 应用。


4.jpg


核心亮点:

1. 跨端跨框架:使用 Renderless 无渲染组件设计架构,实现了一套代码同时支持 Vue2 / Vue3,PC / Mobile 端,并支持函数级别的逻辑定制和全模板替换,灵活性好、二次开发能力强。


2.组件丰富:PC 端有80+组件,移动端有30+组件,包含高频组件 Table、Tree、Select 等,内置虚拟滚动,保证大数据场景下的流畅体验,除了业界常见组件之外,我们还提供了一些独有的特色组件,如:Split 面板分割器、IpAddress IP地址输入框、Calendar 日历、Crop 图片裁切等


3. 配置式组件:组件支持模板式和配置式两种使用方式,适合低代码平台,目前团队已经将 OpenTiny 集成到内部的低代码平台,针对低码平台做了大量优化


4. 周边生态齐全:提供了基于 Angular + TypeScript 的 TinyNG 组件库,提供包含 10+ 实用功能、20+ 典型页面的 TinyPro 中后台模板,提供覆盖前端开发全流程的 TinyCLI 工程化工具,提供强大的在线主题配置平台 TinyTheme

vue

js

网站开发

小程序开发

阅读排行

  • 1. 几行代码就能实现Html大转盘抽奖

    大转盘抽奖是网络互动营销的一种常见形式,其通过简单易懂的界面设计,让用户在游戏中体验到乐趣,同时也能增加商家与用户之间的互动。本文将详细介绍如何使用HTML,CSS和JavaScript来实现大转盘抽奖的功能。

    查看详情
  • 2. 浙江省同区域公司地址变更详细流程

    提前准备好所有需要的资料,包含:房屋租赁合同、房产证、营业执照正副本、代理人身份证正反面、承诺书(由于我们公司其中一区域已有注册另外一公司,所以必须需要承诺书)

    查看详情
  • 3. 微信支付商户申请接入流程

    微信支付,是微信向有出售物品/提供服务需求的商家提供推广销售、支付收款、经营分析的整套解决方案,包括多种支付方式,如JSAPI支付、小程序支付、APP支付H5支付等支付方式接入。

    查看详情
  • 4. 阿里云域名ICP网络备案流程

    根据《互联网信息服务管理办法》以及《非经营性互联网信息服务备案管理办法》,国家对非经营性互联网信息服务实行备案制度,对经营性互联网信息服务实行许可制度。

    查看详情
  • 5. 微信小程序申请注册流程

    微信小程序注册流程与微信公众号较为相似,同时微信小程序支持通过已认证的微信公众号进行注册申请,无需进行单独认证即可使用,同一个已认证微信公众号可同时绑定注册多个小程序。

    查看详情