ElementPlus插件的安装和使用

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) : '访客'
  }
})