ElementPlus插件的安裝和使用
ElementPlus插件安裝和使用
npm install element-plus --save
src/main.ts新增
// 關(guān)鍵節(jié)點:全局注冊 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>
<!--
主布局:企業(yè)級前端系統(tǒng)標(biāo)準(zhǔn)骨架
1. 左側(cè)為多級導(dǎo)航菜單(AppAsideMenu 組件,參考 Element Plus 多級菜單官方樣式)
2. 上方為頭部工具欄(AppHeaderBar 組件,可放用戶信息/全局操作/設(shè)置)
3. 中間為主內(nèi)容區(qū)(router-view 占位,渲染路由對應(yīng)頁面)
4. el-container 嵌套結(jié)構(gòu)保證響應(yīng)式和樣式隔離
-->
<el-container class="main-layout">
<!-- 側(cè)邊欄:寬度固定,可后續(xù)接入收縮/權(quán)限等功能 -->
<el-aside width="220px" class="aside-menu">
<!-- 多級菜單組件(所有菜單內(nèi)容均可配置擴展) -->
<AppAsideMenu />
</el-aside>
<!-- 右側(cè)主區(qū):頭部 + 主內(nèi)容區(qū) -->
<el-container>
<!-- 頭部欄(頂部工具區(qū),可放Logo、面包屑、用戶等) -->
<el-header height="56px" class="header-bar">
<AppHeaderBar />
</el-header>
<!-- 主內(nèi)容區(qū):所有頁面的內(nèi)容都渲染在這里 -->
<el-main class="main-content">
<router-view />
<!-- router-view 占位,動態(tài)加載當(dāng)前路由組件 -->
</el-main>
</el-container>
</el-container>
</template>
<script setup lang="ts">
/**
* 主布局文件 MainLayout.vue
* - 負責(zé)所有頁面的基礎(chǔ)框架搭建
* - 內(nèi)部依賴兩個核心基礎(chǔ)組件(AppAsideMenu、AppHeaderBar),各自單獨維護
* - 可通過 provide/inject、Pinia、props、slots 等方式進行全局交互
*/
import AppAsideMenu from '@/components/AppAsideMenu.vue' // 左側(cè)多級菜單
import AppHeaderBar from '@/components/AppHeaderBar.vue' // 頂部工具欄
</script>
<style scoped>
/* 主布局整體撐滿視口 */
.main-layout {
height: 100vh; /* 100%視口高度,撐滿瀏覽器 */
}
/* 側(cè)邊欄區(qū)域樣式,參考 Element Plus 官方側(cè)欄 */
.aside-menu {
background: var(--el-color-primary-light-9, #f5f7fa); /* 默認(rèn)淡色,也可自定義主題色 */
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;
}
/* 主內(nèi)容區(qū),推薦采用留白設(shè)計,便于擴展儀表盤/表格/圖表等 */
.main-content {
padding: 24px;
background: #f5f6fa; /* 與 Element Plus 設(shè)計語言一致 */
min-height: 100%;
/* 可以加overflow-y: auto,支持內(nèi)容溢出滾動 */
}
</style>
touch src/components/AppAsideMenu.vue
<template>
<!--
AppAsideMenu 組件 —— 系統(tǒng)側(cè)邊多級導(dǎo)航菜單
- 采用 Element Plus <el-menu> 及 <el-sub-menu> 實現(xiàn)多級菜單結(jié)構(gòu)
- 支持路由自動高亮,icon與菜單文本自定義
- 可作為權(quán)限系統(tǒng)和國際化菜單的基礎(chǔ)
- 推薦后期用配置數(shù)據(jù)+遞歸渲染(此Demo為手寫靜態(tài)結(jié)構(gòu),易理解)
-->
<el-menu
:default-active="activeMenu" <!-- 當(dāng)前路由對應(yīng)菜單自動高亮 -->
class="el-menu-vertical-demo" <!-- 自定義樣式class -->
background-color="#f5f7fa" <!-- 菜單背景色,與EP官方一致 -->
text-color="#333" <!-- 默認(rèn)文字顏色 -->
active-text-color="#409EFF" <!-- 選中項高亮色(EP主色) -->
:collapse="false" <!-- 是否折疊菜單,支持響應(yīng)式 -->
router <!-- 啟用路由模式,點擊菜單自動跳轉(zhuǎn) -->
>
<!-- 一級菜單,含圖標(biāo)及文本 -->
<el-sub-menu index="1">
<template #title>
<el-icon><Menu /></el-icon>
<span>主導(dǎo)航</span>
</template>
<!-- 二級菜單:首頁(直接跳轉(zhuǎn)到 /) -->
<el-menu-item index="/">首頁</el-menu-item>
<!-- 二級菜單:帶三級子菜單的演示 -->
<el-sub-menu index="1-2">
<template #title>
<el-icon><Setting /></el-icon>
<span>系統(tǒng)設(shè)置</span>
</template>
<!-- 三級菜單項,可按需擴展 -->
<el-menu-item index="/setting1">設(shè)置1</el-menu-item>
<el-menu-item index="/setting2">設(shè)置2</el-menu-item>
</el-sub-menu>
</el-sub-menu>
<!-- 其它一級或多級菜單項,可繼續(xù)添加 -->
<!--
<el-menu-item index="/profile">
<el-icon><User /></el-icon>
<span>個人中心</span>
</el-menu-item>
-->
</el-menu>
</template>
<script setup lang="ts">
/**
* AppAsideMenu.vue
* - 項目側(cè)邊多級菜單組件
* - 支持動態(tài)路由高亮、圖標(biāo)自定義、權(quán)限拓展
* - 推薦后續(xù)遞歸化和配置驅(qū)動
*/
import { useRoute } from 'vue-router'
import { computed } from 'vue'
import { Menu, Setting } from '@element-plus/icons-vue' // Element Plus官方icon
// 1. 獲取當(dāng)前路由信息(用于菜單高亮)
const route = useRoute()
// 2. 計算當(dāng)前激活菜單項(以route.path為基準(zhǔn),確保跳轉(zhuǎn)/刷新自動同步高亮)
const activeMenu = computed(() => route.path)
// 3. 推薦擴展:
// - 菜單項數(shù)組 + 遞歸渲染(適配權(quán)限/多語言)
// - 支持 collapse 響應(yīng)式收縮(如引入左側(cè)折疊功能)
// - 可注入用戶角色實現(xiàn)動態(tài)菜單
</script>
<style scoped>
/* 側(cè)邊菜單整體樣式 */
.el-menu-vertical-demo {
border-right: none; /* 視覺簡潔,無右側(cè)邊線 */
min-height: 100vh; /* 高度撐滿側(cè)邊 */
width: 100%; /* 占滿aside寬度 */
background: inherit; /* 跟隨外層背景,可自定義主題 */
}
/* 圖標(biāo)與文本的間距優(yōu)化(EP官方推薦8px) */
.el-menu .el-icon {
margin-right: 8px;
}
</style>
touch src/components/AppHeaderBar.vue
<template>
<!--
AppHeaderBar 組件 —— 頂部全局工具欄
1. 左側(cè):可放Logo、系統(tǒng)標(biāo)題、面包屑等
2. 右側(cè):用戶區(qū)(頭像+用戶名+下拉菜單)、全局操作(如設(shè)置、切換主題、通知等)
3. 推薦所有交互通過props/inject/Pinia進行解耦
4. 業(yè)務(wù)區(qū)塊可通過slot拓展
-->
<div class="header-bar-inner">
<!-- 左側(cè)區(qū)域:Logo/系統(tǒng)名(可改成slot) -->
<div class="left">
<span class="title">企業(yè)管理平臺</span>
</div>
<!-- 右側(cè)區(qū)域:用戶/操作區(qū) -->
<div class="right">
<!-- 用戶頭像,可換成后端頭像或本地上傳 -->
<el-avatar size="small" style="margin-right: 8px;">
<!-- 推薦用后端下發(fā)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>
<!-- 用戶操作下拉菜單:個人中心、登錄/登出、設(shè)置等 -->
<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>
<!-- 登錄/登出根據(jù)狀態(tài)切換 -->
<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">設(shè)置</el-dropdown-item>
<!-- 可繼續(xù)添加國際化/主題切換等全局操作 -->
</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: 'zhangsan@example.com', // 假定郵箱
avatarUrl: '' // 可留空
})
// 用戶登出
const logout = () => user.logout()
// 跳個人中心(路由跳轉(zhuǎn)或彈窗,具體業(yè)務(wù)接入)
const toProfile = () => {
// 這里可用router.push('/profile')或emit事件
}
// 打開設(shè)置(建議彈窗或跳轉(zhuǎn)設(shè)置頁)
const openSettings = () => {
// 打開設(shè)置彈窗/頁面
}
</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 組件 —— 首頁內(nèi)容區(qū)
1. 歡迎區(qū):顯示當(dāng)前用戶信息與典型操作按鈕
2. 典型按鈕示例:演示EP主按鈕/默認(rèn)/危險等
3. Table樣例:可直接擴展為業(yè)務(wù)表格
4. 所有內(nèi)容布局留有擴展空間,便于后續(xù)嵌入圖表/分析/卡片等
-->
<div class="home-box">
<!-- 歡迎欄及右側(cè)操作按鈕 -->
<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>
<!-- 典型按鈕示例區(qū) -->
<el-card class="mb-4">
<h3>典型按鈕示例</h3>
<el-button type="primary" class="mr-2">主要按鈕</el-button>
<el-button>默認(rèn)按鈕</el-button>
<el-button type="danger" class="ml-2">危險按鈕</el-button>
</el-card>
<!-- Table 樣例區(qū) -->
<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
* - 首頁內(nèi)容區(qū)/儀表盤
* - 展示典型按鈕、表格,預(yù)留后續(xù)擴展入口
* - 與用戶Pinia狀態(tài)聯(lián)動(如用戶信息刷新)
* - 兼容新Store結(jié)構(gòu),業(yè)務(wù)store全部按modules分文件
*/
import { ref } from 'vue'
import { useUserStore } from '@/store/modules/user' // 新結(jié)構(gòu)的用戶Store
const userStore = useUserStore()
/**
* 刷新用戶信息
* 調(diào)用store action(一般實際會發(fā)起API請求)
*/
const refreshUser = () => userStore.fetchUser()
/**
* 顯示圖表
* 實際項目可彈窗/跳轉(zhuǎn)或渲染圖表組件
*/
const addChart = () => {
// TODO: 集成圖表組件(如ECharts)
}
// 表格數(shù)據(jù)樣例,可直接擴展為API動態(tài)獲取
const tableData = ref([
{ date: '2023-05-22', name: '張三', address: '上海市普陀區(qū)金沙江路' },
{ date: '2023-05-21', name: '李四', address: '北京市海淀區(qū)西二旗' },
{ date: '2023-05-20', name: '王五', address: '廣州市天河區(qū)體育西路' }
])
</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分文件解耦業(yè)務(wù)路由,方便維護和權(quán)限擴展
* 2. 自動合并所有模塊路由,支持無限擴展
* 3. 掛載全局主布局,所有頁面默認(rèn)走統(tǒng)一布局
*/
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
// 1. 按模塊導(dǎo)入路由
import homeRoutes from './modules/home'
import systemRoutes from './modules/system'
// import profileRoutes from './modules/profile' // 可繼續(xù)擴展
// 2. 主路由結(jié)構(gòu)(包含主布局和子頁面)
// - 所有頁面都在MainLayout下渲染,子路由負責(zé)頁面內(nèi)容
const routes: Array<RouteRecordRaw> = [
{
path: '/',
component: () => import('@/layouts/MainLayout.vue'),
children: [
...homeRoutes, // 首頁
...systemRoutes, // 系統(tǒng)設(shè)置
// ...profileRoutes, // 其它模塊
// 可擴展更多業(yè)務(wù)模塊
]
}
// 可擴展如login/404等特殊路由,不走主布局
]
// 3. 創(chuàng)建路由實例,使用HTML5 History模式
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
mkdir src/router/modules
touch src/router/modules/home.ts
/**
* home.ts
* 首頁相關(guān)路由配置(可按需擴展更多子頁面)
*/
import { RouteRecordRaw } from 'vue-router'
const homeRoutes: RouteRecordRaw[] = [
{
path: '/',
name: 'Home',
component: () => import('@/views/AppHome.vue'),
meta: {
title: '首頁',
icon: 'Menu' // 方便和菜單系統(tǒng)關(guān)聯(lián)
}
}
]
export default homeRoutes
touch src/router/modules/system.ts
/**
* system.ts
* 系統(tǒng)設(shè)置相關(guān)路由(可對應(yīng)Element Plus多級菜單中的系統(tǒng)設(shè)置)
*/
import { RouteRecordRaw } from 'vue-router'
const systemRoutes: RouteRecordRaw[] = [
{
path: '/system',
name: 'System',
component: () => import('@/layouts/MainLayout.vue'), // 復(fù)用主布局
meta: {
title: '系統(tǒng)設(shè)置',
icon: 'Setting'
},
children: [
{
path: 'setting1',
name: 'SystemSetting1',
component: () => import('@/views/SystemSetting1.vue'),
meta: { title: '設(shè)置1' }
},
{
path: 'setting2',
name: 'SystemSetting2',
component: () => import('@/views/SystemSetting2.vue'),
meta: { title: '設(shè)置2' }
}
]
}
]
export default systemRoutes
mkdir src/store/types && touch src/store/types/user.ts
/**
* 用戶模塊相關(guān)類型
* 按Google級標(biāo)準(zhǔn)獨立維護,便于多人協(xié)作和類型擴展
*/
export interface UserInfo {
id: string
name: string
email: string
avatarUrl?: string
isLoggedIn: boolean
// 可擴展如角色、權(quán)限、token等
}
mkdir src/store/modules && touch src/store/modules/user.ts
/**
* 用戶模塊 Pinia Store
* - 最大化注釋,適合中大型項目
* - 所有類型全部引自 types
* - 推薦actions僅做狀態(tài)變更和業(yè)務(wù)分發(fā),異步API獨立service層
*/
import { defineStore } from 'pinia'
import type { UserInfo } from '../types/user'
/**
* 推薦:state用工廠函數(shù)返回,避免全局狀態(tài)污染
*/
export const useUserStore = defineStore('user', {
// 1. State: 用戶基本信息,登錄狀態(tài)等
state: (): UserInfo => ({
id: '',
name: '訪客',
email: '',
avatarUrl: '',
isLoggedIn: false
}),
// 2. Actions: 所有業(yè)務(wù)相關(guān)操作(登錄、登出、拉取用戶信息等)
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異步獲取,推薦實際業(yè)務(wù)中封裝獨立service)
*/
async fetchUser() {
// TODO: 調(diào)用真實接口,以下為模擬數(shù)據(jù)
const res = {
id: '1',
name: '張三',
email: 'zhangsan@example.com',
avatarUrl: 'https://api.dicebear.com/8.x/pixel-art/svg?seed=user'
}
this.login(res)
}
},
// 3. Getters: 推薦分文件復(fù)雜業(yè)務(wù)單獨抽取
getters: {
/**
* 用戶昵稱首字母大寫
*/
displayName: (state): string => state.name ? state.name.charAt(0).toUpperCase() + state.name.slice(1) : '訪客'
}
})
浙公網(wǎng)安備 33010602011771號