Vue Material Admin: 基于 Vue 3 + Vuetify 3 的现代管理后台模板
开源 2.3k+ Stars 的 Material Design 管理后台模板深度解析,从技术架构到最佳实践。
项目简介
Vue Material Admin 是一个基于 Vue 3 和 Vuetify 3 构建的现代化管理后台模板。项目在 GitHub 上获得了 2.3k+ Stars 和 583 Forks,是 Vue 生态中最受欢迎的管理后台模板之一。
在线预览
核心技术栈
| 技术 | 版本 | 说明 |
|---|---|---|
| Vue | 3.5+ | 渐进式 JavaScript 框架 |
| Vuetify | 3.11+ | Material Design 组件库 |
| TypeScript | 5.x | 类型安全的开发体验 |
| Vite | 6.x | 闪电般快速的开发服务器 |
| Pinia | 2.x | 直观的 Vue 状态管理 |
| Vue Router | 4.x | 官方路由解决方案 |
技术架构解析
项目结构
code
src/
├── api/ # API 服务层,统一封装 HTTP 请求
├── components/ # 可复用 Vue 组件
├── composables/ # Vue Composables(组合式函数)
├── layouts/ # 布局组件(侧边栏、头部等)
├── plugins/ # 插件配置
│ ├── vuetify/ # Vuetify 主题配置
│ ├── i18n/ # 国际化配置
│ └── msw/ # Mock Service Worker
├── router/ # Vue Router 路由配置
├── store/ # Pinia 状态管理
├── types/ # TypeScript 类型定义
├── utils/ # 工具函数
├── views/ # 页面组件
├── scss/ # 全局样式
├── App.vue # 根组件
└── main.ts # 应用入口核心模块设计
1. API 服务层
项目采用统一的 API 服务封装模式,简化 HTTP 请求处理:
typescript
// src/api/index.ts
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'
class ApiService {
private instance: AxiosInstance
constructor(baseURL: string) {
this.instance = axios.create({
baseURL,
timeout: 30000,
})
this.setupInterceptors()
}
private setupInterceptors() {
// 请求拦截器
this.instance.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
(error) => Promise.reject(error)
)
// 响应拦截器
this.instance.interceptors.response.use(
(response) => response.data,
(error) => {
if (error.response?.status === 401) {
// 处理 Token 过期
localStorage.removeItem('token')
window.location.href = '/login'
}
return Promise.reject(error)
}
)
}
async get<T>(url: string, config?: AxiosRequestConfig) {
return this.instance.get<T>(url, config)
}
async post<T>(url: string, data?: any, config?: AxiosRequestConfig) {
return this.instance.post<T>(url, data, config)
}
async put<T>(url: string, data?: any, config?: AxiosRequestConfig) {
return this.instance.put<T>(url, data, config)
}
async delete<T>(url: string, config?: AxiosRequestConfig) {
return this.instance.delete<T>(url, config)
}
}
export default new ApiService(import.meta.env.VITE_API_BASE_URL)2. 状态管理 (Pinia)
使用 Pinia 进行状态管理,代码更加直观和类型安全:
typescript
// src/store/auth.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import authApi from '@/api/auth'
interface User {
id: string
name: string
email: string
avatar?: string
roles: string[]
}
export const useAuthStore = defineStore('auth', () => {
const user = ref<User | null>(null)
const token = ref<string | null>(localStorage.getItem('token'))
const loading = ref(false)
const isAuthenticated = computed(() => !!token.value)
const isAdmin = computed(() => user.value?.roles.includes('admin'))
const userName = computed(() => user.value?.name || 'Guest')
async function login(credentials: { email: string; password: string }) {
loading.value = true
try {
const { data } = await authApi.login(credentials)
token.value = data.token
user.value = data.user
localStorage.setItem('token', data.token)
return { success: true }
} catch (error: any) {
return { success: false, message: error.message }
} finally {
loading.value = false
}
}
async function logout() {
try {
await authApi.logout()
} finally {
token.value = null
user.value = null
localStorage.removeItem('token')
}
}
async function fetchUser() {
if (!token.value) return
try {
const { data } = await authApi.getUser()
user.value = data
} catch {
logout()
}
}
return {
user,
token,
loading,
isAuthenticated,
isAdmin,
userName,
login,
logout,
fetchUser,
}
})3. 路由守卫
typescript
// src/router/guards.ts
import type { Router } from 'vue-router'
import { useAuthStore } from '@/store/auth'
export function setupRouterGuards(router: Router) {
router.beforeEach(async (to, from, next) => {
const authStore = useAuthStore()
// 设置页面标题
document.title = to.meta.title
? `${to.meta.title} - Vue Material Admin`
: 'Vue Material Admin'
// 公开路由
if (to.meta.public) {
return next()
}
// 需要登录
if (to.meta.requiresAuth && !authStore.isAuthenticated) {
return next({ name: 'Login', query: { redirect: to.fullPath } })
}
// 需要管理员权限
if (to.meta.requiresAdmin && !authStore.isAdmin) {
return next({ name: 'Dashboard' })
}
next()
})
}Vuetify 3 主题配置
自定义主题
typescript
// src/plugins/vuetify/theme.ts
import { defineTheme } from 'vuetify'
export default defineTheme({
defaultTheme: 'light',
themes: {
light: {
colors: {
primary: '#2196F3',
secondary: '#FFC107',
error: '#F44336',
warning: '#FF9800',
info: '#00BCD4',
success: '#4CAF50',
background: '#FAFAFA',
surface: '#FFFFFF',
},
},
dark: {
colors: {
primary: '#64B5F6',
secondary: '#FFD54F',
error: '#EF5350',
warning: '#FFB74D',
info: '#4DD0E1',
success: '#81C784',
background: '#121212',
surface: '#1E1E1E',
},
},
},
})组件默认配置
typescript
// src/plugins/vuetify/defaults.ts
import { defineDefaults } from 'vuetify'
export default defineDefaults({
VBtn: {
variant: 'flat',
rounded: 'lg',
},
VCard: {
rounded: 'lg',
elevation: 2,
},
VTextField: {
variant: 'outlined',
density: 'comfortable',
},
VSelect: {
variant: 'outlined',
density: 'comfortable',
},
VDataTable: {
hover: true,
},
})快速上手
环境要求
- Node.js 18+
- Yarn 或 npm
安装与启动
bash
# 克隆项目
git clone https://github.com/tookit/vue-material-admin.git
# 进入目录
cd vue-material-admin
# 安装依赖
yarn install
# 启动开发服务器
yarn dev
# 生产构建
yarn build
# 类型检查
yarn typecheck
# 代码格式化
yarn lint环境变量配置
bash
# .env
VITE_APP_TITLE=Vue Material Admin
VITE_API_BASE_URL=http://localhost:3000/api
VITE_APP_PORT=9527核心功能模块
1. 认证模块
- 登录/登出
- Token 管理
- 记住密码
- 密码强度检测
2. 仪表盘
- 销售数据概览
- ApexCharts 图表
- 实时数据更新
3. 用户管理
- 用户列表
- 用户增删改查
- 角色权限管理
4. 组件示例
- 表格 (VDataTable)
- 表单验证
- 富文本编辑器
- 日历组件 (FullCalendar)
- 文件上传
- 拖拽排序
5. 国际化
- Vue I18n 集成
- 中英文切换
- 动态语言切换
最佳实践
1. 组件开发规范
vue
<!-- components/MyComponent.vue -->
<script setup lang="ts">
interface Props {
title: string
items: Item[]
loading?: boolean
}
interface Emits {
(e: 'select', item: Item): void
(e: 'delete', id: string): void
}
const props = withDefaults(defineProps<Props>(), {
loading: false,
})
const emit = defineEmits<Emits>()
const selectedItem = ref<Item | null>(null)
function handleSelect(item: Item) {
selectedItem.value = item
emit('select', item)
}
</script>
<template>
<v-card>
<v-card-title>{{ title }}</v-card-title>
<v-card-text>
<v-progress-linear v-if="loading" indeterminate />
<v-list v-else>
<v-list-item
v-for="item in items"
:key="item.id"
@click="handleSelect(item)"
>
{{ item.name }}
</v-list-item>
</v-list>
</v-card-text>
</v-card>
</template>2. Composable 封装
typescript
// composables/usePagination.ts
import { ref, computed } from 'vue'
interface PaginationOptions {
page?: number
pageSize?: number
total?: number
}
export function usePagination(options: PaginationOptions = {}) {
const page = ref(options.page || 1)
const pageSize = ref(options.pageSize || 10)
const total = ref(options.total || 0)
const totalPages = computed(() =>
Math.ceil(total.value / pageSize.value)
)
const hasNextPage = computed(() =>
page.value < totalPages.value
)
const hasPrevPage = computed(() =>
page.value > 1
)
function nextPage() {
if (hasNextPage.value) {
page.value++
}
}
function prevPage() {
if (hasPrevPage.value) {
page.value--
}
}
function setPage(newPage: number) {
page.value = Math.max(1, Math.min(newPage, totalPages.value))
}
return {
page,
pageSize,
total,
totalPages,
hasNextPage,
hasPrevPage,
nextPage,
prevPage,
setPage,
}
}性能优化
1. 路由懒加载
typescript
// src/router/index.ts
const routes = [
{
path: '/dashboard',
name: 'Dashboard',
component: () => import('@/views/Dashboard.vue'),
},
{
path: '/users',
name: 'Users',
component: () => import('@/views/Users.vue'),
},
]2. 组件按需引入
typescript
// vite.config.ts
import { defineConfig } from 'vite'
import vuetify from 'vite-plugin-vuetify'
export default defineConfig({
plugins: [
vuetify({ autoImport: true }),
],
optimizeDeps: {
include: ['vue', 'vuetify', 'pinia'],
},
})3. 图片优化
vue
<v-img
src="/images/logo.png"
lazy-src="/images/logo-placeholder.png"
max-width="200"
max-height="100"
/>部署建议
Vercel 部署
bash
# vercel.json
{
"buildCommand": "yarn build",
"outputDirectory": "dist",
"framework": "vite"
}Docker 部署
dockerfile
FROM node:18-alpine AS builder
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
COPY . .
RUN yarn build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]总结
Vue Material Admin 是一个功能完善、代码质量高的管理后台模板,适合快速启动中后台项目。其技术选型现代化,代码结构清晰,具有良好的可扩展性。
项目亮点:
- 采用最新的 Vue 3 + Composition API
- TypeScript 提供完整的类型支持
- Vuetify 3 Material Design 设计语言
- Vite 带来的极速开发体验
- 完善的权限管理和国际化支持
- 活跃的开源社区维护
如果你正在寻找一个高质量的 Vue 管理后台模板,Vue Material Admin 绝对值得一试。
相关链接: