从Vue2迁移到Vue3:Naive Ui Admin升级指南与注意事项

从Vue2迁移到Vue3:Naive Ui Admin升级指南与注意事项

【免费下载链接】naive-ui-admin Naive Ui Admin 是一个基于 vue3,vite2,TypeScript 的中后台解决方案,它使用了最新的前端技术栈,并提炼了典型的业务模型,页面,包括二次封装组件、动态菜单、权限校验、粒子化权限控制等功能,它可以帮助你快速搭建企业级中后台项目,相信不管是从新技术使用还是其他方面,都能帮助到你,持续更新中。 【免费下载链接】naive-ui-admin 项目地址: https://gitcode.com/gh_mirrors/na/naive-ui-admin

引言:为什么要升级到Vue3?

你是否还在为Vue2项目的性能瓶颈和TypeScript支持不足而烦恼?随着前端技术的快速发展,Vue3带来了诸多革命性的改进,如Composition API、更好的TypeScript集成、更高效的虚拟DOM等。本文将以Naive Ui Admin为例,详细介绍从Vue2迁移到Vue3的全过程,帮助你顺利完成项目升级,提升开发效率和应用性能。

读完本文后,你将能够:

  • 了解Vue2与Vue3的核心差异
  • 掌握Naive Ui Admin项目的升级步骤
  • 解决迁移过程中常见的问题
  • 充分利用Vue3的新特性优化项目

一、Vue2与Vue3核心差异对比

1.1 性能优化

Vue3在性能方面做了重大改进,主要体现在以下几个方面:

特性Vue2Vue3
虚拟DOM全量重写基于Proxy的响应式系统,按需更新
编译优化基础优化静态提升、补丁标记、缓存事件处理函数
体积较大通过Tree-shaking减小体积,核心库体积减少约41%
内存占用较高优化了内存占用,减少约55%

1.2 核心API变化

Vue3引入了Composition API,替代了Vue2的Options API,主要变化如下:

mermaid

二、Naive Ui Admin项目升级准备

2.1 环境要求

在开始升级前,请确保你的开发环境满足以下要求:

  • Node.js >= 16.0.0
  • npm >= 7.0.0 或 pnpm >= 6.0.0
  • Git

2.2 项目备份

在进行任何重大变更前,建议先备份项目:

git clone https://gitcode.com/gh_mirrors/na/naive-ui-admin naive-ui-admin-vue2
cd naive-ui-admin-vue2
git branch -c backup/vue2
git checkout -b upgrade/vue3

2.3 依赖升级

首先,我们需要更新package.json中的核心依赖:

{
  "dependencies": {
    "vue": "^3.5.5",
    "vue-router": "^4.4.5",
    "pinia": "^2.2.2",
    "naive-ui": "^2.39.0"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^3.2.0",
    "typescript": "^4.9.5",
    "vite": "^5.4.5"
  }
}

安装更新后的依赖:

pnpm install

三、核心代码迁移

3.1 入口文件改造

Vue3的入口文件与Vue2有较大差异,我们需要修改src/main.ts:

// Vue2
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

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

// Vue3
import { createApp } from 'vue'
import App from './App.vue'
import { setupStore } from '@/store'
import router, { setupRouter } from './router'
import { setupNaive, setupDirectives } from '@/plugins'

async function bootstrap() {
  const app = createApp(App)
  
  // 挂载状态管理
  setupStore(app)
  
  // 注册全局常用的 naive-ui 组件
  setupNaive(app)
  
  // 注册全局自定义指令
  setupDirectives(app)
  
  // 挂载路由
  setupRouter(app)
  
  // 路由准备就绪后挂载 APP 实例
  await router.isReady()
  
  app.mount('#app', true)
}

void bootstrap()

3.2 状态管理从Vuex迁移到Pinia

Vue3推荐使用Pinia替代Vuex,以下是迁移示例:

// Vue2 Vuex
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    user
  }
})

// Vue3 Pinia
// store/index.ts
import type { App } from 'vue'
import { createPinia } from 'pinia'

const store = createPinia()

export function setupStore(app: App<Element>) {
  app.use(store)
}

export { store }

3.3 路由系统升级

Vue Router 4与Vue Router 3有一些重要变化,需要更新src/router/index.ts:

// Vue2
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    }
  ]
})

// Vue3
import { App } from 'vue'
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
import { setupRouterGuards } from './guards'

export const constantRouter: RouteRecordRaw[] = [
  {
    path: '/',
    name: 'Root',
    redirect: '/dashboard'
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes: constantRouter,
  strict: true,
  scrollBehavior: () => ({ left: 0, top: 0 })
})

export function setupRouter(app: App) {
  app.use(router)
  setupRouterGuards(router)
}

export default router

四、组件迁移实战

4.1 基础组件改造

Vue3的单文件组件(SFC)语法有一些变化,主要体现在script标签上:

<!-- Vue2 -->
<template>
  <div>{{ message }}</div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello Vue2'
    }
  }
}
</script>

<!-- Vue3 -->
<template>
  <div>{{ message }}</div>
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const message = ref('Hello Vue3')
</script>

4.2 表单组件升级

以src/views/comp/form/basic.vue为例,展示Vue3中表单的使用方式:

<template>
  <BasicForm
    submitButtonText="提交预约"
    layout="horizontal"
    :schemas="schemas"
    @submit="handleSubmit"
  >
    <template #statusSlot="{ model, field }">
      <n-input v-model:value="model[field]" />
    </template>
  </BasicForm>
</template>

<script lang="ts" setup>
import { BasicForm, FormSchema } from '@/components/Form/index'
import { useMessage } from 'naive-ui'

const schemas: FormSchema[] = [
  {
    field: 'name',
    component: 'NInput',
    label: '姓名',
    rules: [{ required: true, message: '请输入姓名', trigger: ['blur'] }]
  }
]

const message = useMessage()

function handleSubmit(values: Recordable) {
  message.success(JSON.stringify(values))
}
</script>

4.3 表格组件升级

以下是src/views/comp/table/basic.vue的Vue3实现:

<template>
  <BasicTable
    title="表格列表"
    :columns="columns"
    :request="loadDataTable"
    :row-key="(row) => row.id"
    ref="actionRef"
    :actionColumn="actionColumn"
  />
</template>

<script lang="ts" setup>
import { BasicTable, TableAction } from '@/components/Table'
import { getTableList } from '@/api/table/list'
import { columns } from './basicColumns'
import { useDialog, useMessage } from 'naive-ui'
import { DeleteOutlined, EditOutlined } from '@vicons/antd'

const message = useMessage()
const dialog = useDialog()
const actionRef = ref()

const params = reactive({
  pageSize: 5,
  name: 'NaiveAdmin'
})

const actionColumn = reactive({
  width: 180,
  title: '操作',
  key: 'action',
  fixed: 'right',
  render(record) {
    return h(TableAction, {
      actions: createActions(record)
    })
  }
})

const loadDataTable = async (res) => {
  return await getTableList({ ...params, ...res })
}

function createActions(record) {
  return [
    {
      label: '编辑',
      icon: EditOutlined,
      onClick: handleEdit.bind(null, record)
    },
    {
      label: '删除',
      icon: DeleteOutlined,
      onClick: handleDelete.bind(null, record)
    }
  ]
}
</script>

五、迁移常见问题及解决方案

5.1 响应式系统变化

Vue3使用ref和reactive替代了Vue2的Object.defineProperty,需要注意以下转换:

// Vue2
data() {
  return {
    count: 0,
    user: {
      name: 'John'
    }
  }
}

// Vue3
const count = ref(0)
const user = reactive({
  name: 'John'
})

// 使用ref时需要通过.value访问
console.log(count.value) // 0

// 但在模板中可以直接使用,无需.value
// <div>{{ count }}</div>

5.2 生命周期钩子调整

Vue3的生命周期钩子有较大变化,以下是对应关系:

Vue2Vue3
beforeCreatesetup()
createdsetup()
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeDestroyonBeforeUnmount
destroyedonUnmounted

5.3 事件总线替代方案

Vue3中移除了$on、$off和$once方法,推荐使用第三方库或Pinia实现事件总线:

// store/modules/eventBus.ts
import { defineStore } from 'pinia'
import { ref } from 'vue'

export const useEventBusStore = defineStore('eventBus', () => {
  const events = ref(new Map())

  function on(event: string, callback: Function) {
    if (!events.value.has(event)) {
      events.value.set(event, [])
    }
    events.value.get(event)!.push(callback)
  }

  function off(event: string, callback: Function) {
    if (!events.value.has(event)) return
    const index = events.value.get(event)!.indexOf(callback)
    if (index > -1) {
      events.value.get(event)!.splice(index, 1)
    }
  }

  function emit(event: string, ...args: any[]) {
    if (!events.value.has(event)) return
    events.value.get(event)!.forEach((callback: Function) => {
      callback(...args)
    })
  }

  return { on, off, emit }
})

六、Naive UI组件库适配

6.1 安装与配置

Naive UI是一个基于Vue3的组件库,安装后需要在项目中进行配置:

// src/plugins/naive.ts
import { App } from 'vue'
import {
  NButton,
  NCard,
  NInput,
  // 导入其他需要的组件
} from 'naive-ui'

const naiveComponents = [NButton, NCard, NInput]

export function setupNaive(app: App) {
  naiveComponents.forEach(component => {
    app.component(component.name, component)
  })
}

6.2 主题配置

Naive UI支持主题定制,可以在src/App.vue中配置:

<template>
  <NConfigProvider :theme="getDarkTheme" :theme-overrides="getThemeOverrides">
    <AppProvider>
      <RouterView />
    </AppProvider>
  </NConfigProvider>
</template>

<script lang="ts" setup>
import { computed } from 'vue'
import { darkTheme } from 'naive-ui'
import { useDesignSettingStore } from '@/store/modules/designSetting'
import { lighten } from '@/utils/index'

const designStore = useDesignSettingStore()

const getThemeOverrides = computed(() => {
  const appTheme = designStore.appTheme
  const lightenStr = lighten(designStore.appTheme, 6)
  return {
    common: {
      primaryColor: appTheme,
      primaryColorHover: lightenStr
    }
  }
})

const getDarkTheme = computed(() => designStore.darkTheme ? darkTheme : undefined)
</script>

七、TypeScript集成

7.1 类型定义

Vue3对TypeScript有更好的支持,建议为组件和API添加类型定义:

// src/components/Form/src/types/form.ts
import type { VNodeChild } from 'vue'
import type { FormItemRule } from 'naive-ui'

export interface FormSchema {
  field: string
  label: string
  labelMessage?: VNodeChild
  component: ComponentType
  componentProps?: Recordable
  rules?: FormItemRule[]
  slot?: string
}

7.2 组合式API类型支持

在使用组合式API时,可以为ref和reactive添加类型:

import { ref, reactive } from 'vue'

interface User {
  name: string
  age: number
}

const count = ref<number>(0)
const user = reactive<User>({
  name: 'John',
  age: 30
})

八、性能优化建议

8.1 按需导入

使用unplugin-vue-components插件实现组件按需导入:

// vite.config.ts
import Components from 'unplugin-vue-components/vite'
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  plugins: [
    Components({
      resolvers: [NaiveUiResolver()]
    })
  ]
})

8.2 代码分割

利用Vue3的异步组件和动态导入功能优化加载性能:

// src/router/modules/dashboard.ts
import { RouteRecordRaw } from 'vue-router'

const dashboardRoute: RouteRecordRaw = {
  path: '/dashboard',
  name: 'Dashboard',
  component: () => import('@/views/dashboard/console/console.vue')
}

export default dashboardRoute

九、测试与部署

9.1 本地测试

完成代码迁移后,运行以下命令启动开发服务器:

pnpm dev

访问http://localhost:3000,检查应用是否正常运行。

9.2 构建优化

使用Vite构建生产版本:

pnpm build

可以通过以下命令分析构建结果:

pnpm report

9.3 部署

将构建产物部署到服务器:

# 示例:部署到GitHub Pages
pnpm deploy

十、总结与展望

10.1 迁移成果

通过本文介绍的步骤,我们成功将Naive Ui Admin从Vue2迁移到Vue3,主要成果包括:

  • 升级到最新的Vue3生态系统(Vue 3.5.5、Vue Router 4.4.5、Pinia 2.2.2)
  • 采用Composition API重构核心组件
  • 集成TypeScript提升代码质量和可维护性
  • 使用Naive UI组件库优化UI体验

10.2 后续优化方向

迁移完成后,可以考虑以下优化方向:

  1. 全面使用组合式API重构遗留Options API代码
  2. 利用Vue3的Teleport和Suspense特性增强用户体验
  3. 实现更细粒度的组件拆分和复用
  4. 优化构建流程,进一步减小包体积

10.3 学习资源

推荐以下资源深入学习Vue3和Naive UI:

通过持续学习和实践,你将能够充分利用Vue3的强大功能,构建更高质量的前端应用。

附录:常见问题解答

Q1: 迁移后项目启动报错怎么办?

A1: 首先检查Node.js版本是否符合要求,然后删除node_modules和pnpm-lock.yaml,重新安装依赖:

rm -rf node_modules pnpm-lock.yaml
pnpm install

Q2: 如何处理第三方库不兼容Vue3的问题?

A2: 可以尝试寻找替代库或使用@vue/compat帮助迁移:

pnpm add @vue/compat@^3.5.5

Q3: 迁移后单元测试失败如何解决?

A3: Vue3推荐使用Vue Test Utils v2进行测试,需要更新测试代码以适应新的API:

pnpm add @vue/test-utils@next --dev

更多问题请参考官方迁移指南或提交issue获取帮助。

【免费下载链接】naive-ui-admin Naive Ui Admin 是一个基于 vue3,vite2,TypeScript 的中后台解决方案,它使用了最新的前端技术栈,并提炼了典型的业务模型,页面,包括二次封装组件、动态菜单、权限校验、粒子化权限控制等功能,它可以帮助你快速搭建企业级中后台项目,相信不管是从新技术使用还是其他方面,都能帮助到你,持续更新中。 【免费下载链接】naive-ui-admin 项目地址: https://gitcode.com/gh_mirrors/na/naive-ui-admin

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值