Vue3企业级实战:从零构建高性能后台管理系统框架
一、技术架构设计
现代后台管理系统技术选型:
- Vue3:Composition API + TypeScript
- Vite:下一代前端构建工具
- Pinia:状态管理方案
- Vue Router:路由管理
- Element Plus:UI组件库
二、项目初始化与配置
1. 使用Vite创建项目
npm create vite@latest admin-system --template vue-ts
cd admin-system
npm install
npm install pinia vue-router element-plus axios
2. 目录结构设计
src/
├── api/ # API接口管理
├── assets/ # 静态资源
├── components/ # 公共组件
├── composables/ # 组合式函数
├── router/ # 路由配置
├── stores/ # Pinia状态管理
├── styles/ # 全局样式
├── types/ # TypeScript类型定义
├── utils/ # 工具函数
├── views/ # 页面组件
├── App.vue # 根组件
└── main.ts # 入口文件
三、核心功能实现
1. 动态路由配置
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{
path: '/login',
component: () => import('@/views/Login.vue'),
meta: { requiresAuth: false }
},
{
path: '/',
component: () => import('@/layouts/MainLayout.vue'),
meta: { requiresAuth: true },
children: [
{
path: '/dashboard',
component: () => import('@/views/Dashboard.vue'),
meta: { title: '控制台', icon: 'dashboard' }
},
// 其他路由...
]
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
// 路由守卫
router.beforeEach(async (to, from, next) => {
const authStore = useAuthStore()
if (to.meta.requiresAuth && !authStore.token) {
next('/login')
} else {
next()
}
})
export default router
2. Pinia状态管理
// stores/auth.ts
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { login, logout } from '@/api/auth'
export const useAuthStore = defineStore('auth', () => {
const token = ref(localStorage.getItem('token') || '')
const userInfo = ref(null)
const setToken = (newToken: string) => {
token.value = newToken
localStorage.setItem('token', newToken)
}
const clearToken = () => {
token.value = ''
localStorage.removeItem('token')
}
const loginAction = async (credentials: LoginForm) => {
const res = await login(credentials)
setToken(res.token)
userInfo.value = res.user
}
const logoutAction = async () => {
await logout()
clearToken()
userInfo.value = null
}
return { token, userInfo, loginAction, logoutAction }
})
四、高级功能实现
1. 权限控制指令
// directives/permission.ts
import type { Directive } from 'vue'
export const permission: Directive = {
mounted(el, binding) {
const { value } = binding
const authStore = useAuthStore()
if (value && !authStore.hasPermission(value)) {
el.parentNode?.removeChild(el)
}
}
}
// main.ts注册
app.directive('permission', permission)
// 使用示例
<button v-permission="'user:create'">创建用户</button>
2. 动态主题切换
// composables/useTheme.ts
import { ref, watchEffect } from 'vue'
export function useTheme() {
const theme = ref(localStorage.getItem('theme') || 'light')
watchEffect(() => {
document.documentElement.setAttribute('data-theme', theme.value)
localStorage.setItem('theme', theme.value)
})
const toggleTheme = () => {
theme.value = theme.value === 'light' ? 'dark' : 'light'
}
return { theme, toggleTheme }
}
// 样式定义
:root[data-theme="light"] {
--bg-color: #ffffff;
--text-color: #333333;
}
:root[data-theme="dark"] {
--bg-color: #1a1a1a;
--text-color: #f0f0f0;
}
五、性能优化方案
1. 组件懒加载
// 路由懒加载
const UserManagement = defineAsyncComponent(() =>
import('@/views/system/UserManagement.vue')
)
// 图片懒加载
<img v-lazy="imageUrl" alt="description" />
2. API请求缓存
// utils/request.ts
const cache = new Map()
export async function cachedRequest(key: string, requestFn: () => Promise) {
if (cache.has(key)) {
return cache.get(key)
}
const data = await requestFn()
cache.set(key, data)
// 设置缓存过期时间
setTimeout(() => {
cache.delete(key)
}, 5 * 60 * 1000) // 5分钟
return data
}
// 使用示例
const userList = await cachedRequest('user-list', () => getUserList())
六、典型页面实现
1. 数据表格页
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { getTableData } from '@/api/table'
const tableData = ref([])
const loading = ref(false)
const pagination = ref({
current: 1,
pageSize: 10,
total: 0
})
const fetchData = async () => {
try {
loading.value = true
const res = await getTableData({
page: pagination.value.current,
size: pagination.value.pageSize
})
tableData.value = res.data
pagination.value.total = res.total
} finally {
loading.value = false
}
}
const handlePageChange = (current: number) => {
pagination.value.current = current
fetchData()
}
onMounted(fetchData)
</script>
<template>
<el-table :data="tableData" v-loading="loading">
<el-table-column prop="name" label="名称" />
<el-table-column prop="status" label="状态" />
<!-- 其他列 -->
</el-table>
<el-pagination
v-model:current-page="pagination.current"
:page-size="pagination.pageSize"
:total="pagination.total"
@current-change="handlePageChange"
/>
</template>