1. 首先安装依赖
npm install vue@next element-plus @element-plus/icons-vue
2. 主界面布局组件 (MainLayout.vue)
<template>
<div class="main-layout">
<!-- 侧边栏 -->
<el-aside :width="sidebarWidth" class="sidebar">
<!-- Logo区域 -->
<div class="logo">
<img src="/favicon.ico" alt="Logo" v-if="!isCollapse" />
<span v-if="!isCollapse">管理系统</span>
<span v-else>系统</span>
</div>
<!-- 菜单 -->
<el-menu
:default-active="activeMenu"
:collapse="isCollapse"
:unique-opened="true"
router
background-color="#304156"
text-color="#bfcbd9"
active-text-color="#409EFF"
class="menu"
>
<el-menu-item index="/dashboard">
<el-icon><House /></el-icon>
<template #title>仪表盘</template>
</el-menu-item>
<el-sub-menu index="/user">
<template #title>
<el-icon><User /></el-icon>
<span>用户管理</span>
</template>
<el-menu-item index="/user/list">用户列表</el-menu-item>
<el-menu-item index="/user/roles">角色管理</el-menu-item>
<el-menu-item index="/user/permissions">权限管理</el-menu-item>
</el-sub-menu>
<el-sub-menu index="/content">
<template #title>
<el-icon><Document /></el-icon>
<span>内容管理</span>
</template>
<el-menu-item index="/content/articles">文章管理</el-menu-item>
<el-menu-item index="/content/categories">分类管理</el-menu-item>
<el-menu-item index="/content/tags">标签管理</el-menu-item>
</el-sub-menu>
<el-menu-item index="/system">
<el-icon><Setting /></el-icon>
<template #title>系统设置</template>
</el-menu-item>
<el-menu-item index="/analytics">
<el-icon><DataAnalysis /></el-icon>
<template #title>数据分析</template>
</el-menu-item>
</el-menu>
</el-aside>
<!-- 主要内容区域 -->
<div class="main-container">
<!-- 顶部导航栏 -->
<el-header class="header">
<div class="header-left">
<!-- 折叠按钮 -->
<el-button
type="text"
@click="toggleSidebar"
class="collapse-btn"
>
<el-icon size="20">
<Fold v-if="!isCollapse" />
<Expand v-else />
</el-icon>
</el-button>
<!-- 面包屑导航 -->
<el-breadcrumb separator="/" class="breadcrumb">
<el-breadcrumb-item
v-for="item in breadcrumbs"
:key="item.path"
:to="item.path"
>
{{ item.title }}
</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="header-right">
<!-- 搜索框 -->
<el-input
v-model="searchText"
placeholder="搜索..."
prefix-icon="Search"
class="search-box"
clearable
/>
<!-- 通知 -->
<el-badge :value="notificationCount" class="notification">
<el-button type="text" circle>
<el-icon><Bell /></el-icon>
</el-button>
</el-badge>
<!-- 用户信息 -->
<el-dropdown @command="handleUserCommand" class="user-info">
<span class="user-dropdown">
<el-avatar :size="32" :src="userInfo.avatar">
{{ userInfo.name?.charAt(0) }}
</el-avatar>
<span class="username">{{ userInfo.name }}</span>
<el-icon><ArrowDown /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="profile">个人资料</el-dropdown-item>
<el-dropdown-item command="settings">账户设置</el-dropdown-item>
<el-dropdown-item divided command="logout">退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</el-header>
<!-- 页面内容 -->
<el-main class="content">
<router-view />
</el-main>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import {
House,
User,
Document,
Setting,
DataAnalysis,
Search,
Bell,
ArrowDown,
Fold,
Expand
} from '@element-plus/icons-vue'
const route = useRoute()
const router = useRouter()
// 响应式数据
const isCollapse = ref(false)
const searchText = ref('')
const notificationCount = ref(5)
// 用户信息
const userInfo = ref({
name: '管理员',
avatar: '', // 头像URL,为空时显示首字母
role: 'administrator'
})
// 计算属性
const sidebarWidth = computed(() => {
return isCollapse.value ? '64px' : '240px'
})
const activeMenu = computed(() => {
return route.path
})
// 面包屑导航
const breadcrumbs = computed(() => {
const pathArray = route.path.split('/').filter(Boolean)
const breadcrumbs = []
let currentPath = ''
pathArray.forEach((segment, index) => {
currentPath += `/${segment}`
let title = segment.charAt(0).toUpperCase() + segment.slice(1)
// 自定义标题映射
const titleMap = {
dashboard: '仪表盘',
user: '用户管理',
list: '用户列表',
roles: '角色管理',
permissions: '权限管理',
content: '内容管理',
articles: '文章管理',
categories: '分类管理',
tags: '标签管理',
system: '系统设置',
analytics: '数据分析'
}
if (titleMap[segment]) {
title = titleMap[segment]
}
breadcrumbs.push({
title,
path: currentPath
})
})
return breadcrumbs
})
// 方法
const toggleSidebar = () => {
isCollapse.value = !isCollapse.value
}
const handleUserCommand = (command) => {
switch (command) {
case 'profile':
router.push('/profile')
break
case 'settings':
router.push('/settings')
break
case 'logout':
logout()
break
}
}
const logout = () => {
// 清除本地存储的token等信息
localStorage.removeItem('token')
sessionStorage.clear()
// 跳转到登录页
router.push('/login')
}
</script>
<style scoped>
.main-layout {
height: 100vh;
display: flex;
}
/* 侧边栏样式 */
.sidebar {
background-color: #304156;
transition: width 0.3s;
overflow: hidden;
}
.logo {
height: 60px;
display: flex;
align-items: center;
justify-content: center;
background-color: #2b2f3a;
color: #fff;
font-size: 18px;
font-weight: bold;
border-bottom: 1px solid #434a50;
}
.logo img {
width: 24px;
height: 24px;
margin-right: 8px;
}
.menu {
border-right: none;
height: calc(100vh - 60px);
}
/* 主容器样式 */
.main-container {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* 头部导航栏样式 */
.header {
background-color: #fff;
border-bottom: 1px solid #e4e7ed;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
box-shadow: 0 1px 4px rgba(0,21,41,.08);
}
.header-left {
display: flex;
align-items: center;
}
.collapse-btn {
margin-right: 20px;
padding: 0;
font-size: 18px;
color: #606266;
}
.breadcrumb {
margin-left: 0;
}
.header-right {
display: flex;
align-items: center;
gap: 20px;
}
.search-box {
width: 200px;
}
.notification {
cursor: pointer;
}
.user-info {
cursor: pointer;
}
.user-dropdown {
display: flex;
align-items: center;
gap: 8px;
color: #303133;
}
.username {
font-weight: 500;
}
/* 内容区域样式 */
.content {
background-color: #f0f2f5;
padding: 20px;
overflow-y: auto;
}
/* 响应式设计 */
@media (max-width: 768px) {
.search-box {
display: none;
}
.breadcrumb {
display: none;
}
.username {
display: none;
}
}
</style>
3. 路由配置 (router/index.js)
import { createRouter, createWebHistory } from 'vue-router'
import MainLayout from '@/components/MainLayout.vue'
const routes = [
{
path: '/',
redirect: '/dashboard'
},
{
path: '/',
component: MainLayout,
children: [
{
path: 'dashboard',
name: 'Dashboard',
component: () => import('@/views/Dashboard.vue'),
meta: { title: '仪表盘' }
},
{
path: 'user/list',
name: 'UserList',
component: () => import('@/views/user/UserList.vue'),
meta: { title: '用户列表' }
},
{
path: 'user/roles',
name: 'UserRoles',
component: () => import('@/views/user/Roles.vue'),
meta: { title: '角色管理' }
},
{
path: 'user/permissions',
name: 'UserPermissions',
component: () => import('@/views/user/Permissions.vue'),
meta: { title: '权限管理' }
},
{
path: 'content/articles',
name: 'Articles',
component: () => import('@/views/content/Articles.vue'),
meta: { title: '文章管理' }
},
{
path: 'content/categories',
name: 'Categories',
component: () => import('@/views/content/Categories.vue'),
meta: { title: '分类管理' }
},
{
path: 'content/tags',
name: 'Tags',
component: () => import('@/views/content/Tags.vue'),
meta: { title: '标签管理' }
},
{
path: 'system',
name: 'System',
component: () => import('@/views/System.vue'),
meta: { title: '系统设置' }
},
{
path: 'analytics',
name: 'Analytics',
component: () => import('@/views/Analytics.vue'),
meta: { title: '数据分析' }
},
{
path: 'profile',
name: 'Profile',
component: () => import('@/views/Profile.vue'),
meta: { title: '个人资料' }
},
{
path: 'settings',
name: 'Settings',
component: () => import('@/views/Settings.vue'),
meta: { title: '账户设置' }
}
]
},
{
path: '/login',
name: 'Login',
component: () => import('@/views/Login.vue'),
meta: { title: '登录' }
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
4. 示例页面组件 (views/Dashboard.vue)
<template>
<div class="dashboard">
<h1>欢迎使用管理系统</h1>
<el-row :gutter="20" class="stats-row">
<el-col :span="6">
<el-card class="stat-card">
<div class="stat-content">
<div class="stat-number">1,234</div>
<div class="stat-label">总用户数</div>
</div>
<div class="stat-icon">
<el-icon size="30" color="#409EFF"><User /></el-icon>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="stat-card">
<div class="stat-content">
<div class="stat-number">567</div>
<div class="stat-label">文章数量</div>
</div>
<div class="stat-icon">
<el-icon size="30" color="#67C23A"><Document /></el-icon>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="stat-card">
<div class="stat-content">
<div class="stat-number">89</div>
<div class="stat-label">今日访问</div>
</div>
<div class="stat-icon">
<el-icon size="30" color="#E6A23C"><View /></el-icon>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="stat-card">
<div class="stat-content">
<div class="stat-number">12</div>
<div class="stat-label">待处理</div>
</div>
<div class="stat-icon">
<el-icon size="30" color="#F56C6C"><Bell /></el-icon>
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script setup>
import { User, Document, View, Bell } from '@element-plus/icons-vue'
</script>
<style scoped>
.dashboard h1 {
margin-bottom: 30px;
color: #303133;
}
.stats-row {
margin-bottom: 30px;
}
.stat-card {
position: relative;
overflow: hidden;
}
.stat-content {
text-align: center;
}
.stat-number {
font-size: 28px;
font-weight: bold;
color: #303133;
margin-bottom: 8px;
}
.stat-label {
color: #909399;
font-size: 14px;
}
.stat-icon {
position: absolute;
right: 20px;
top: 50%;
transform: translateY(-50%);
}
</style>
5. 全局样式 (styles/global.css)
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background-color: #f0f2f5;
}
#app {
height: 100vh;
}
6. main.js 入口文件
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
const app = createApp(App)
// 注册所有图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.use(router)
app.use(ElementPlus)
app.mount('#app')
这个Vue主界面包含了以下功能特性:
🎯 主要功能
-
左侧菜单:可折叠的侧边栏,支持多级菜单
-
顶部导航栏:包含面包屑、搜索、通知、用户信息
-
响应式设计:适配移动端和桌面端
-
路由集成:与Vue Router完美结合
-
用户管理:下拉菜单支持个人资料、设置和退出
🛠️ 技术特点
-
Vue 3 Composition API
-
Element Plus UI框架
-
响应式布局
-
CSS Grid & Flexbox
-
组件化设计