ElementPlus插件安装和使用
npm install element-plus --save
src/main.ts新增
// 关键节点:全局注册 Element Plus,包含样式
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css' // 核心样式
app.use(ElementPlus) // 注册全局
mkdir -p src/layouts src/components src/views src/router src/store
touch src/layouts/MainLayout.vue
<template>
<!--
主布局:企业级前端系统标准骨架
1. 左侧为多级导航菜单(AppAsideMenu 组件,参考 Element Plus 多级菜单官方样式)
2. 上方为头部工具栏(AppHeaderBar 组件,可放用户信息/全局操作/设置)
3. 中间为主内容区(router-view 占位,渲染路由对应页面)
4. el-container 嵌套结构保证响应式和样式隔离
-->
<el-container class="main-layout">
<!-- 侧边栏:宽度固定,可后续接入收缩/权限等功能 -->
<el-aside width="220px" class="aside-menu">
<!-- 多级菜单组件(所有菜单内容均可配置扩展) -->
<AppAsideMenu />
</el-aside>
<!-- 右侧主区:头部 + 主内容区 -->
<el-container>
<!-- 头部栏(顶部工具区,可放Logo、面包屑、用户等) -->
<el-header height="56px" class="header-bar">
<AppHeaderBar />
</el-header>
<!-- 主内容区:所有页面的内容都渲染在这里 -->
<el-main class="main-content">
<router-view />
<!-- router-view 占位,动态加载当前路由组件 -->
</el-main>
</el-container>
</el-container>
</template>
<script setup lang="ts">
/**
* 主布局文件 MainLayout.vue
* - 负责所有页面的基础框架搭建
* - 内部依赖两个核心基础组件(AppAsideMenu、AppHeaderBar),各自单独维护
* - 可通过 provide/inject、Pinia、props、slots 等方式进行全局交互
*/
import AppAsideMenu from '@/components/AppAsideMenu.vue' // 左侧多级菜单
import AppHeaderBar from '@/components/AppHeaderBar.vue' // 顶部工具栏
</script>
<style scoped>
/* 主布局整体撑满视口 */
.main-layout {
height: 100vh; /* 100%视口高度,撑满浏览器 */
}
/* 侧边栏区域样式,参考 Element Plus 官方侧栏 */
.aside-menu {
background: var(--el-color-primary-light-9, #f5f7fa); /* 默认淡色,也可自定义主题色 */
min-height: 100vh;
border-right: 1px solid #ebeef5; /* 视觉分隔线 */
/* 可按需添加 transition 支持折叠动画 */
}
/* 顶部工具栏,样式贴近 Element Plus 官方 Demo */
.header-bar {
background: #fff;
border-bottom: 1px solid #ebeef5;
box-shadow: 0 1px 4px rgba(0,21,41,0.04); /* 细微阴影增强层次 */
z-index: 100;
}
/* 主内容区,推荐采用留白设计,便于扩展仪表盘/表格/图表等 */
.main-content {
padding: 24px;
background: #f5f6fa; /* 与 Element Plus 设计语言一致 */
min-height: 100%;
/* 可以加overflow-y: auto,支持内容溢出滚动 */
}
</style>
touch src/components/AppAsideMenu.vue
<template>
<!--
AppAsideMenu 组件 ------ 系统侧边多级导航菜单
- 采用 Element Plus <el-menu> 及 <el-sub-menu> 实现多级菜单结构
- 支持路由自动高亮,icon与菜单文本自定义
- 可作为权限系统和国际化菜单的基础
- 推荐后期用配置数据+递归渲染(此Demo为手写静态结构,易理解)
-->
<el-menu
:default-active="activeMenu" <!-- 当前路由对应菜单自动高亮 -->
class="el-menu-vertical-demo" <!-- 自定义样式class -->
background-color="#f5f7fa" <!-- 菜单背景色,与EP官方一致 -->
text-color="#333" <!-- 默认文字颜色 -->
active-text-color="#409EFF" <!-- 选中项高亮色(EP主色) -->
:collapse="false" <!-- 是否折叠菜单,支持响应式 -->
router <!-- 启用路由模式,点击菜单自动跳转 -->
>
<!-- 一级菜单,含图标及文本 -->
<el-sub-menu index="1">
<template #title>
<el-icon><Menu /></el-icon>
<span>主导航</span>
</template>
<!-- 二级菜单:首页(直接跳转到 /) -->
<el-menu-item index="/">首页</el-menu-item>
<!-- 二级菜单:带三级子菜单的演示 -->
<el-sub-menu index="1-2">
<template #title>
<el-icon><Setting /></el-icon>
<span>系统设置</span>
</template>
<!-- 三级菜单项,可按需扩展 -->
<el-menu-item index="/setting1">设置1</el-menu-item>
<el-menu-item index="/setting2">设置2</el-menu-item>
</el-sub-menu>
</el-sub-menu>
<!-- 其它一级或多级菜单项,可继续添加 -->
<!--
<el-menu-item index="/profile">
<el-icon><User /></el-icon>
<span>个人中心</span>
</el-menu-item>
-->
</el-menu>
</template>
<script setup lang="ts">
/**
* AppAsideMenu.vue
* - 项目侧边多级菜单组件
* - 支持动态路由高亮、图标自定义、权限拓展
* - 推荐后续递归化和配置驱动
*/
import { useRoute } from 'vue-router'
import { computed } from 'vue'
import { Menu, Setting } from '@element-plus/icons-vue' // Element Plus官方icon
// 1. 获取当前路由信息(用于菜单高亮)
const route = useRoute()
// 2. 计算当前激活菜单项(以route.path为基准,确保跳转/刷新自动同步高亮)
const activeMenu = computed(() => route.path)
// 3. 推荐扩展:
// - 菜单项数组 + 递归渲染(适配权限/多语言)
// - 支持 collapse 响应式收缩(如引入左侧折叠功能)
// - 可注入用户角色实现动态菜单
</script>
<style scoped>
/* 侧边菜单整体样式 */
.el-menu-vertical-demo {
border-right: none; /* 视觉简洁,无右侧边线 */
min-height: 100vh; /* 高度撑满侧边 */
width: 100%; /* 占满aside宽度 */
background: inherit; /* 跟随外层背景,可自定义主题 */
}
/* 图标与文本的间距优化(EP官方推荐8px) */
.el-menu .el-icon {
margin-right: 8px;
}
</style>
touch src/components/AppHeaderBar.vue
<template>
<!--
AppHeaderBar 组件 ------ 顶部全局工具栏
1. 左侧:可放Logo、系统标题、面包屑等
2. 右侧:用户区(头像+用户名+下拉菜单)、全局操作(如设置、切换主题、通知等)
3. 推荐所有交互通过props/inject/Pinia进行解耦
4. 业务区块可通过slot拓展
-->
<div class="header-bar-inner">
<!-- 左侧区域:Logo/系统名(可改成slot) -->
<div class="left">
<span class="title">企业管理平台</span>
</div>
<!-- 右侧区域:用户/操作区 -->
<div class="right">
<!-- 用户头像,可换成后端头像或本地上传 -->
<el-avatar size="small" style="margin-right: 8px;">
<!-- 推荐用后端下发URL或第三方图像生成器 -->
<img src="https://api.dicebear.com/8.x/pixel-art/svg?seed=user" alt="avatar" />
</el-avatar>
<!-- 用户名(可用pinia或props注入) -->
<span style="margin-right: 16px;">{{ user.name }}</span>
<!-- 用户操作下拉菜单:个人中心、登录/登出、设置等 -->
<el-dropdown>
<span class="el-dropdown-link">
操作 <el-icon><ArrowDown /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="toProfile">个人中心</el-dropdown-item>
<!-- 登录/登出根据状态切换 -->
<el-dropdown-item divided v-if="user.isLoggedIn" @click="logout">登出</el-dropdown-item>
<el-dropdown-item v-else @click="login">登录</el-dropdown-item>
<el-dropdown-item @click="openSettings">设置</el-dropdown-item>
<!-- 可继续添加国际化/主题切换等全局操作 -->
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
</template>
<script setup lang="ts">
/**
* AppHeaderBar.vue
* - 顶部全局工具栏组件
* - 最大化注释,Google级工程可扩展性
* - 所有用户与操作均解耦(可接pinia、props或inject)
*/
import { useUserStore } from '@/store/useUserStore' // 推荐全局pinia管理用户信息
import { ArrowDown } from '@element-plus/icons-vue'
const user = useUserStore()
// 用户登录(可换成弹窗或跳OAuth)
const login = () => user.login({
id: '1', // 假定ID
name: '张三',
email: '[email protected]', // 假定邮箱
avatarUrl: '' // 可留空
})
// 用户登出
const logout = () => user.logout()
// 跳个人中心(路由跳转或弹窗,具体业务接入)
const toProfile = () => {
// 这里可用router.push('/profile')或emit事件
}
// 打开设置(建议弹窗或跳转设置页)
const openSettings = () => {
// 打开设置弹窗/页面
}
</script>
<style scoped>
.header-bar-inner {
display: flex;
justify-content: space-between;
align-items: center;
height: 100%; /* 撑满header高度 */
}
.title {
font-weight: 700;
font-size: 20px;
color: #333;
letter-spacing: 1px;
}
.right {
display: flex;
align-items: center;
}
/* el-avatar/下拉等可自行美化 */
</style>
touch src/views/AppHome.vue
<template>
<!--
AppHome 组件 ------ 首页内容区
1. 欢迎区:显示当前用户信息与典型操作按钮
2. 典型按钮示例:演示EP主按钮/默认/危险等
3. Table样例:可直接扩展为业务表格
4. 所有内容布局留有扩展空间,便于后续嵌入图表/分析/卡片等
-->
<div class="home-box">
<!-- 欢迎栏及右侧操作按钮 -->
<el-row :gutter="24" class="mb-4">
<el-col :span="12">
<h2>欢迎,{{ userStore.displayName }}!</h2>
</el-col>
<el-col :span="12" style="text-align: right;">
<el-button type="primary" @click="refreshUser">刷新用户信息</el-button>
<el-button type="success" @click="addChart" class="ml-2">显示图表</el-button>
</el-col>
</el-row>
<!-- 典型按钮示例区 -->
<el-card class="mb-4">
<h3>典型按钮示例</h3>
<el-button type="primary" class="mr-2">主要按钮</el-button>
<el-button>默认按钮</el-button>
<el-button type="danger" class="ml-2">危险按钮</el-button>
</el-card>
<!-- Table 样例区 -->
<el-card>
<h3>Table 样例</h3>
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="date" label="日期" width="180" />
<el-table-column prop="name" label="姓名" width="180" />
<el-table-column prop="address" label="地址" />
</el-table>
</el-card>
</div>
</template>
<script setup lang="ts">
/**
* AppHome.vue
* - 首页内容区/仪表盘
* - 展示典型按钮、表格,预留后续扩展入口
* - 与用户Pinia状态联动(如用户信息刷新)
* - 兼容新Store结构,业务store全部按modules分文件
*/
import { ref } from 'vue'
import { useUserStore } from '@/store/modules/user' // 新结构的用户Store
const userStore = useUserStore()
/**
* 刷新用户信息
* 调用store action(一般实际会发起API请求)
*/
const refreshUser = () => userStore.fetchUser()
/**
* 显示图表
* 实际项目可弹窗/跳转或渲染图表组件
*/
const addChart = () => {
// TODO: 集成图表组件(如ECharts)
}
// 表格数据样例,可直接扩展为API动态获取
const tableData = ref([
{ date: '2023-05-22', name: '张三', address: '上海市普陀区金沙江路' },
{ date: '2023-05-21', name: '李四', address: '北京市海淀区西二旗' },
{ date: '2023-05-20', name: '王五', address: '广州市天河区体育西路' }
])
</script>
<style scoped>
.home-box {
padding: 20px;
background: #fff;
border-radius: 8px;
}
.mb-4 {
margin-bottom: 24px;
}
.ml-2 {
margin-left: 8px;
}
.mr-2 {
margin-right: 8px;
}
</style>
touch src/router/index.ts
/**
* index.ts
* 路由主入口(Google级模块化,最大化注释)
* 1. 按modules分文件解耦业务路由,方便维护和权限扩展
* 2. 自动合并所有模块路由,支持无限扩展
* 3. 挂载全局主布局,所有页面默认走统一布局
*/
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
// 1. 按模块导入路由
import homeRoutes from './modules/home'
import systemRoutes from './modules/system'
// import profileRoutes from './modules/profile' // 可继续扩展
// 2. 主路由结构(包含主布局和子页面)
// - 所有页面都在MainLayout下渲染,子路由负责页面内容
const routes: Array<RouteRecordRaw> = [
{
path: '/',
component: () => import('@/layouts/MainLayout.vue'),
children: [
...homeRoutes, // 首页
...systemRoutes, // 系统设置
// ...profileRoutes, // 其它模块
// 可扩展更多业务模块
]
}
// 可扩展如login/404等特殊路由,不走主布局
]
// 3. 创建路由实例,使用HTML5 History模式
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
mkdir src/router/modules
touch src/router/modules/home.ts
/**
* home.ts
* 首页相关路由配置(可按需扩展更多子页面)
*/
import { RouteRecordRaw } from 'vue-router'
const homeRoutes: RouteRecordRaw[] = [
{
path: '/',
name: 'Home',
component: () => import('@/views/AppHome.vue'),
meta: {
title: '首页',
icon: 'Menu' // 方便和菜单系统关联
}
}
]
export default homeRoutes
touch src/router/modules/system.ts
/**
* system.ts
* 系统设置相关路由(可对应Element Plus多级菜单中的系统设置)
*/
import { RouteRecordRaw } from 'vue-router'
const systemRoutes: RouteRecordRaw[] = [
{
path: '/system',
name: 'System',
component: () => import('@/layouts/MainLayout.vue'), // 复用主布局
meta: {
title: '系统设置',
icon: 'Setting'
},
children: [
{
path: 'setting1',
name: 'SystemSetting1',
component: () => import('@/views/SystemSetting1.vue'),
meta: { title: '设置1' }
},
{
path: 'setting2',
name: 'SystemSetting2',
component: () => import('@/views/SystemSetting2.vue'),
meta: { title: '设置2' }
}
]
}
]
export default systemRoutes
mkdir src/store/types && touch src/store/types/user.ts
/**
* 用户模块相关类型
* 按Google级标准独立维护,便于多人协作和类型扩展
*/
export interface UserInfo {
id: string
name: string
email: string
avatarUrl?: string
isLoggedIn: boolean
// 可扩展如角色、权限、token等
}
mkdir src/store/modules && touch src/store/modules/user.ts
/**
* 用户模块 Pinia Store
* - 最大化注释,适合中大型项目
* - 所有类型全部引自 types
* - 推荐actions仅做状态变更和业务分发,异步API独立service层
*/
import { defineStore } from 'pinia'
import type { UserInfo } from '../types/user'
/**
* 推荐:state用工厂函数返回,避免全局状态污染
*/
export const useUserStore = defineStore('user', {
// 1. State: 用户基本信息,登录状态等
state: (): UserInfo => ({
id: '',
name: '访客',
email: '',
avatarUrl: '',
isLoggedIn: false
}),
// 2. Actions: 所有业务相关操作(登录、登出、拉取用户信息等)
actions: {
/**
* 用户登录
* @param info 用户信息对象(建议后端返回后再保存)
*/
login(info: Omit<UserInfo, 'isLoggedIn'>) {
this.id = info.id
this.name = info.name
this.email = info.email
this.avatarUrl = info.avatarUrl
this.isLoggedIn = true
},
/**
* 用户登出(重置所有用户信息)
*/
logout() {
this.id = ''
this.name = '访客'
this.email = ''
this.avatarUrl = ''
this.isLoggedIn = false
},
/**
* 拉取用户信息(通常配合API异步获取,推荐实际业务中封装独立service)
*/
async fetchUser() {
// TODO: 调用真实接口,以下为模拟数据
const res = {
id: '1',
name: '张三',
email: '[email protected]',
avatarUrl: 'https://api.dicebear.com/8.x/pixel-art/svg?seed=user'
}
this.login(res)
}
},
// 3. Getters: 推荐分文件复杂业务单独抽取
getters: {
/**
* 用户昵称首字母大写
*/
displayName: (state): string => state.name ? state.name.charAt(0).toUpperCase() + state.name.slice(1) : '访客'
}
})