Vue 3工程化实践与组件设计

核心任务概述

本次项目实训聚焦Vue 3前端工程化配置与全局组件开发,目标是通过模块化设计提升代码复用率,并建立规范的前后端协作流程。核心任务包括:

  • 使用Pinia实现全局状态管理
  • 基于Ant Design Vue完成响应式布局组件
  • 封装统一的HTTP请求层
工程化配置实践

项目采用Vite构建工具初始化Vue 3 TypeScript模板,引入Router和Pinia

Router:路由管理

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'home',
      component: HomePage,
    },
  ],
})

Pinia:状态管理

全局组件开发

BasicLayout.vue作为基础布局组件,整合导航菜单与页脚:

<template>
  <a-layout class="basic-layout">
    <!-- 顶部导航栏 -->
    <GlobalHeader />
    <!-- 主要内容区域 -->
    <a-layout-content class="main-content">
      <router-view />
    </a-layout-content>
    <!-- 底部版权信息 -->
    <GlobalFooter />
  </a-layout>
</template>

<script setup lang="ts">
import GlobalHeader from '@/components/GlobalHeader.vue'
import GlobalFooter from '@/components/GlobalFooter.vue'
</script>

<style scoped>
.basic-layout {
  background: none;
}

.main-content {
  width: 100%;
  padding: 0;
  background: none;
  margin: 0;
}
</style>

import GlobalHeader from '@/components/GlobalHeader.vue'

import GlobalFooter from '@/components/GlobalFooter.vue'

将GlobalHeader 和GlobalFooter抽离成组件,结构更清晰

在GlobalHeader.vue中给 GlobalHeader 的菜单组件绑定跳转事件:

import { useRouter } from 'vue-router'
const router = useRouter()

// 处理菜单点击
const handleMenuClick: MenuProps['onClick'] = (e) => {
  const key = e.key as string
  selectedKeys.value = [key]
  // 跳转到对应页面
  if (key.startsWith('/')) {
    router.push(key)
  }
}

高亮同步

刷新页面后 ,发现当前菜单项并没有高亮,所以需要同步路由的更新到菜单项高亮。

同步高亮原理:

1. 点击菜单时,Ant Design 组件已经通过 v-model 绑定 current 变量实现了高亮。

2. 刷新页面时,需要获取到当前 URL 路径,然后修改 current 变量的值,从而实现同步。

使用Vue Router的 afterEach 路由钩子实现,每次改变路由或刷新页面时都会自动更新 current 的值,从而实现高亮

// 当前选中菜单
const selectedKeys = ref<string[]>(['/'])
// 监听路由变化,更新当前选中菜单
router.afterEach((to, from, next) => {
  selectedKeys.value = [to.path]
})
请求层封装方案

Axios拦截器配置包含:

  • 错误统一处理逻辑:
import axios from 'axios'
import { message } from 'ant-design-vue'


// 创建 Axios 实例
const myAxios = axios.create({
  baseURL: 'http://localhost:8080/api',
  timeout: 60000,
  withCredentials: true,
})

// 全局请求拦截器
myAxios.interceptors.request.use(
  function (config) {
    // Do something before request is sent
    return config
  },
  function (error) {
    // Do something with request error
    return Promise.reject(error)
  },
)

// 全局响应拦截器
myAxios.interceptors.response.use(
  function (response) {
    const { data } = response
    // 未登录
    if (data.code === 40100) {
      // 不是获取用户信息的请求,并且用户目前不是已经在用户登录页面,则跳转到登录页面
      if (
        !response.request.responseURL.includes('user/get/login') &&
        !window.location.pathname.includes('/user/login')
      ) {
        message.warning('请先登录')
        window.location.href = `/user/login?redirect=${window.location.href}`
      }
    }
    return response
  },
  function (error) {
    // Any status codes that falls outside the range of 2xx cause this function to trigger
    // Do something with response error
    return Promise.reject(error)
  },
)

export default myAxios
自动生成请求代码

如果采用传统开发方式,针对每个请求都要单独编写代码,很麻烦。 所以使用 OpenAPI 工具,直接根据后端接口文档自动生成前端请求代码即可,这种方式会比 AI 生成更可控。

// 根据后端接口生成前端请求和 TS 模型代码
// npm run openapi2ts
export default {
  requestLibPath: "import request from '@/request'",
  // schemaPath: 'Your OpenAPI schema path',
  schemaPath: 'http://localhost:8080/api/v3/api-docs',
  serversPath: './src',
}

生成的模型直接应用于Pinia Action,确保前后端参数类型一致。

经验总结
  1. 模块化设计使布局组件复用率提升40%
  2. 自动生成的API代码减少手动声明类型的时间消耗
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐