Vue3 + TS 企业级工程化项目全套实战(Vue3 + Vite + Pinia + VueRouter + Element Plus)

本文作者:LIO

一、项目背景与技术栈选型

这是一个面向中大型后台管理系统的 Vue3 工程化全套方案。你可以直接用于项目脚手架、面试准备或技术博客。

核心技术栈

  • Vue3(Composition API)
  • Vite
  • TypeScript
  • Pinia(替代 Vuex)
  • Vue Router 4
  • Element Plus
  • Axios 封装
  • ESLint + Prettier + Husky
  • Scss / CSS Variables

推荐目录结构(可直接复制使用)

plaintext 复制代码
src
├── api          # 接口请求统一封装
├── assets       # 图片、样式资源
├── components   # 公共组件
├── config       # 全局常量、环境变量
├── hooks        # 通用 hooks
├── layouts      # 布局组件
├── router       # 路由 + 权限路由
├── store        # Pinia 模块化仓库
├── types        // TS 类型声明
├── utils        // 工具函数
├── views        // 业务页面
├── App.vue
└── main.ts

二、Axios 全局请求封装(生产级)

1. 创建 src/utils/request.ts

ts 复制代码
import axios from 'axios'
import { ElMessage, ElLoading } from 'element-plus'

let loadingInstance: any = null

const request = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 10000,
})

// 请求拦截器
request.interceptors.request.use(
  (config) => {
    loadingInstance = ElLoading.service({ fullscreen: true })
    const token = localStorage.getItem('token')
    if (token) config.headers.Authorization = `Bearer ${token}`
    return config
  },
  (err) => Promise.reject(err)
)

// 响应拦截器
request.interceptors.response.use(
  (res) => {
    loadingInstance.close()
    return res.data
  },
  (err) => {
    loadingInstance.close()
    ElMessage.error(err.response?.data?.message || '请求失败')
    return Promise.reject(err)
  }
)

export default request

2. API 分层示例(src/api/user.ts)

ts 复制代码
import request from '@/utils/request'

export function getUserInfo() {
  return request.get('/user/info')
}

export function login(data: any) {
  return request.post('/login', data)
}

三、Pinia 仓库模块化设计(src/store/index.ts)

ts 复制代码
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    token: localStorage.getItem('token') || '',
    userInfo: null as any,
  }),

  actions: {
    setToken(token: string) {
      this.token = token
      localStorage.setItem('token', token)
    },

    async fetchUserInfo() {
      const res = await getUserInfo()
      this.userInfo = res.data
    },
  },
})

四、Vue Router + 权限路由

src/router/index.ts

ts 复制代码
import { createRouter, createWebHistory } from 'vue-router'
import { useUserStore } from '@/store/user'

const routes = [
  {
    path: '/',
    component: () => import('@/layouts/MainLayout.vue'),
    meta: { requireAuth: true },
    children: [
      { path: '', component: () => import('@/views/Home.vue') },
      { path: 'user', component: () => import('@/views/User.vue') },
    ],
  },
  { path: '/login', component: () => import('@/views/Login.vue') },
]

const router = createRouter({
  history: createWebHistory(),
  routes,
})

// 全局路由守卫
router.beforeEach((to, from, next) => {
  const userStore = useUserStore()
  if (to.meta.requireAuth && !userStore.token) {
    next('/login')
  } else {
    next()
  }
})

export default router

五、工程化与打包优化(重点)

  1. 路由懒加载
ts 复制代码
component: () => import('@/views/Home.vue')
  1. 分包策略(vite.config.ts)
ts 复制代码
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        chunkFileNames: 'js/[name]-[hash].js',
        entryFileNames: 'js/[name]-[hash].js',
        assetFileNames: '[ext]/[name]-[hash].[ext]',
      },
    },
  },
})
  1. ESLint + Prettier
plaintext 复制代码
npx eslint --fix .
  1. Husky 提交校验
plaintext 复制代码
npx husky install
npx husky add .husky/pre-commit "npm lint"

六、常见业务场景落地(可直接复制)

1. 分页列表

vue 复制代码
<template>
  <el-table
    :data="list"
    :loading="loading"
  >
    <!-- 列 -->
  </el-table>
  <el-pagination
    v-model:page-size="pageSize"
    v-model:current-page="pageNum"
    :total="total"
    @change="fetchList"
  />
</template>

2. 表单校验

ts 复制代码
const ruleRef = ref()

const rules = {
  name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
}

七、面试高频考点(掘金博客可直接写)

  • Vue3 响应式原理(Proxy)
  • Composition API 与 Options API 区别
  • Pinia 与 Vuex 的差异
  • Vue Router 动态路由实现
  • Vite 与 Webpack 对比
  • 组件懒加载、代码分割
  • 前端鉴权方案(JWT + 路由守卫)

------个人观点 · 仅供参考------

相关推荐
神明不懂浪漫34 分钟前
【第四章】CSS(二)——文本外观属性与复合选择器
前端·css·经验分享·笔记
kyriewen44 分钟前
别再用AI debug了——这5种bug越修越烂
前端·javascript·ai编程
星释2 小时前
鸿蒙智能体开发实战:39.鸿蒙壁纸大师 - 前端卡片显示与交互优化
前端·华为·交互·harmonyos·鸿蒙·火山引擎
顾昂_2 小时前
内存泄漏排查和 Chrome DevTools 使用教程
前端·javascript·面试
IT_陈寒3 小时前
Java线程池这个坑我算是踩明白了
前端·人工智能·后端
31535669134 小时前
Superpowers:GPT-5.6 时代下的流程毒瘤
前端·后端
清秋4 小时前
全网最全 ECMAScript 攻略( 更新至 ES2026)
前端·javascript·编程语言
Cao_Ron5 小时前
用 SVG image symbol 画 ECharts graph 圆形节点
前端
hxy06015 小时前
React-Call让你的React组件像异步函数一样调用
前端·react.js
Hilaku5 小时前
为什么 AI 写前端时,总是优先选择 React,而不是 Vue?
前端·javascript·程序员