提交文件
This commit is contained in:
412
.qoder/repowiki/zh/content/前端开发指南/Vue组件开发/组件设计模式.md
Normal file
412
.qoder/repowiki/zh/content/前端开发指南/Vue组件开发/组件设计模式.md
Normal file
@@ -0,0 +1,412 @@
|
||||
# 组件设计模式
|
||||
|
||||
<cite>
|
||||
**本文引用的文件**
|
||||
- [frontend/src/App.vue](file://frontend/src/App.vue)
|
||||
- [frontend/src/main.js](file://frontend/src/main.js)
|
||||
- [frontend/src/router/index.js](file://frontend/src/router/index.js)
|
||||
- [frontend/src/views/Layout.vue](file://frontend/src/views/Layout.vue)
|
||||
- [frontend/src/views/Login.vue](file://frontend/src/views/Login.vue)
|
||||
- [frontend/src/views/Dashboard.vue](file://frontend/src/views/Dashboard.vue)
|
||||
- [frontend/src/views/basic/Departments.vue](file://frontend/src/views/basic/Departments.vue)
|
||||
- [frontend/src/views/assessment/Assessments.vue](file://frontend/src/views/assessment/Assessments.vue)
|
||||
- [frontend/src/views/assessment/AssessmentDetail.vue](file://frontend/src/views/assessment/AssessmentDetail.vue)
|
||||
- [frontend/src/stores/user.js](file://frontend/src/stores/user.js)
|
||||
- [frontend/src/stores/app.js](file://frontend/src/stores/app.js)
|
||||
- [frontend/src/stores/index.js](file://frontend/src/stores/index.js)
|
||||
- [frontend/src/api/index.js](file://frontend/src/api/index.js)
|
||||
- [frontend/vite.config.js](file://frontend/vite.config.js)
|
||||
- [frontend/package.json](file://frontend/package.json)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [引言](#引言)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构总览](#架构总览)
|
||||
5. [组件详解](#组件详解)
|
||||
6. [依赖关系分析](#依赖关系分析)
|
||||
7. [性能考量](#性能考量)
|
||||
8. [故障排查指南](#故障排查指南)
|
||||
9. [结论](#结论)
|
||||
10. [附录](#附录)
|
||||
|
||||
## 引言
|
||||
本指南围绕 Vue 组件设计模式,结合仓库中的前端实现,系统阐述组件拆分原则、单一职责与高内聚低耦合理念;容器组件与展示组件的分离;组件抽象与复用策略;组件通信(父子、兄弟、跨级、事件总线);状态管理(全局与局部);组件边界与接口设计;以及测试策略与 Mock 数据实践。目标是帮助读者在实际项目中构建清晰、可维护、可扩展的组件体系。
|
||||
|
||||
## 项目结构
|
||||
前端采用典型的单页应用结构:入口应用、路由、布局、业务视图、状态管理与 API 层。整体遵循“关注点分离”和“按功能域组织”的原则,便于团队协作与长期演进。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
A["main.js<br/>应用入口"] --> B["App.vue<br/>根组件"]
|
||||
A --> C["router/index.js<br/>路由配置"]
|
||||
A --> D["stores/*<br/>Pinia 状态"]
|
||||
A --> E["api/*<br/>API 导出聚合"]
|
||||
B --> F["router-view<br/>动态渲染视图"]
|
||||
F --> G["Layout.vue<br/>布局容器"]
|
||||
G --> H["views/*<br/>业务视图"]
|
||||
subgraph "业务视图"
|
||||
H1["Login.vue"]
|
||||
H2["Dashboard.vue"]
|
||||
H3["basic/Departments.vue"]
|
||||
H4["assessment/Assessments.vue"]
|
||||
H5["assessment/AssessmentDetail.vue"]
|
||||
end
|
||||
G --> H1
|
||||
G --> H2
|
||||
G --> H3
|
||||
G --> H4
|
||||
G --> H5
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [frontend/src/main.js](file://frontend/src/main.js#L1-L24)
|
||||
- [frontend/src/App.vue](file://frontend/src/App.vue#L1-L17)
|
||||
- [frontend/src/router/index.js](file://frontend/src/router/index.js#L1-L116)
|
||||
- [frontend/src/views/Layout.vue](file://frontend/src/views/Layout.vue#L1-L241)
|
||||
|
||||
章节来源
|
||||
- [frontend/src/main.js](file://frontend/src/main.js#L1-L24)
|
||||
- [frontend/src/App.vue](file://frontend/src/App.vue#L1-L17)
|
||||
- [frontend/src/router/index.js](file://frontend/src/router/index.js#L1-L116)
|
||||
|
||||
## 核心组件
|
||||
- 应用入口与根组件
|
||||
- 入口负责注册插件、挂载应用;根组件提供语言环境与路由出口。
|
||||
- 路由层
|
||||
- 定义页面级路由、嵌套路由与导航守卫,统一设置标题与鉴权跳转。
|
||||
- 布局容器
|
||||
- 提供侧边栏、面包屑、头部用户信息与主内容区,承载业务视图切换与动画。
|
||||
- 业务视图
|
||||
- 各功能域页面(如登录、仪表盘、基础数据、考核管理等),承担数据加载、交互与展示。
|
||||
- 状态管理
|
||||
- Pinia Store 提供用户态与应用态(如侧边栏折叠、科室树)管理。
|
||||
- API 聚合
|
||||
- 统一导出各模块 API 方法,便于视图组件按需引入。
|
||||
|
||||
章节来源
|
||||
- [frontend/src/App.vue](file://frontend/src/App.vue#L1-L17)
|
||||
- [frontend/src/main.js](file://frontend/src/main.js#L1-L24)
|
||||
- [frontend/src/router/index.js](file://frontend/src/router/index.js#L1-L116)
|
||||
- [frontend/src/views/Layout.vue](file://frontend/src/views/Layout.vue#L1-L241)
|
||||
- [frontend/src/stores/user.js](file://frontend/src/stores/user.js#L1-L49)
|
||||
- [frontend/src/stores/app.js](file://frontend/src/stores/app.js#L1-L31)
|
||||
- [frontend/src/api/index.js](file://frontend/src/api/index.js#L1-L9)
|
||||
|
||||
## 架构总览
|
||||
系统采用“布局容器 + 页面视图 + 状态管理 + API 调用”的分层架构。路由驱动视图切换,Pinia 管理共享状态,Element Plus 提供 UI 基础能力,Vite 提供开发与代理能力。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "运行时"
|
||||
R["浏览器"]
|
||||
V["Vue 3 运行时"]
|
||||
P["Pinia 状态"]
|
||||
E["Element Plus UI"]
|
||||
AX["Axios 请求"]
|
||||
end
|
||||
R --> V
|
||||
V --> E
|
||||
V --> P
|
||||
V --> AX
|
||||
AX --> S["后端服务<br/>http://localhost:8000"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [frontend/src/main.js](file://frontend/src/main.js#L1-L24)
|
||||
- [frontend/vite.config.js](file://frontend/vite.config.js#L1-L22)
|
||||
- [frontend/package.json](file://frontend/package.json#L1-L27)
|
||||
|
||||
## 组件详解
|
||||
|
||||
### 布局容器组件(Layout)
|
||||
- 角色定位
|
||||
- 容器组件:负责页面骨架、菜单渲染、侧边栏折叠、面包屑与用户下拉。
|
||||
- 设计要点
|
||||
- 通过 Pinia 管理侧边栏折叠状态;从 API 加载菜单树并映射为前端菜单项。
|
||||
- 使用路由元信息设置页面标题;在登出时清理状态并跳转登录。
|
||||
- 边界与接口
|
||||
- 依赖:路由实例、用户与应用 Store、菜单 API。
|
||||
- 输出:菜单项数组、折叠状态、路由元信息标题。
|
||||
- 复用策略
|
||||
- 将菜单加载逻辑抽离为可复用的工具函数;对菜单树转换逻辑进行单元测试。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant U as "用户"
|
||||
participant L as "Layout.vue"
|
||||
participant S as "Store(user/app)"
|
||||
participant A as "API(menu)"
|
||||
participant R as "Router"
|
||||
U->>L : 打开页面
|
||||
L->>S : 读取折叠状态/用户信息
|
||||
L->>A : 加载菜单树
|
||||
A-->>L : 返回菜单数据
|
||||
L->>L : 转换为前端菜单项
|
||||
L->>R : 设置页面标题
|
||||
U->>L : 点击菜单/折叠按钮
|
||||
L->>S : 更新折叠状态
|
||||
L->>R : 导航到目标路由
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [frontend/src/views/Layout.vue](file://frontend/src/views/Layout.vue#L73-L125)
|
||||
- [frontend/src/stores/user.js](file://frontend/src/stores/user.js#L1-L49)
|
||||
- [frontend/src/stores/app.js](file://frontend/src/stores/app.js#L1-L31)
|
||||
- [frontend/src/router/index.js](file://frontend/src/router/index.js#L104-L113)
|
||||
|
||||
章节来源
|
||||
- [frontend/src/views/Layout.vue](file://frontend/src/views/Layout.vue#L1-L241)
|
||||
- [frontend/src/stores/user.js](file://frontend/src/stores/user.js#L1-L49)
|
||||
- [frontend/src/stores/app.js](file://frontend/src/stores/app.js#L1-L31)
|
||||
- [frontend/src/router/index.js](file://frontend/src/router/index.js#L104-L113)
|
||||
|
||||
### 登录组件(Login)
|
||||
- 角色定位
|
||||
- 展示组件:负责表单输入、校验与登录交互。
|
||||
- 设计要点
|
||||
- 表单校验规则;调用用户 Store 的登录方法;成功后提示与路由跳转;失败提示。
|
||||
- 边界与接口
|
||||
- 输入:表单数据(用户名/密码);输出:登录结果与路由跳转。
|
||||
- 复用策略
|
||||
- 将表单校验规则与消息提示封装为可复用的组合式函数;对登录流程进行单元测试。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant U as "用户"
|
||||
participant L as "Login.vue"
|
||||
participant S as "Store(user)"
|
||||
participant R as "Router"
|
||||
U->>L : 输入用户名/密码
|
||||
U->>L : 点击登录
|
||||
L->>L : 校验表单
|
||||
alt 校验通过
|
||||
L->>S : 调用 login(username,password)
|
||||
S-->>L : 返回布尔结果
|
||||
alt 成功
|
||||
L->>U : 显示成功消息
|
||||
L->>R : 跳转 /
|
||||
else 失败
|
||||
L->>U : 显示失败消息
|
||||
end
|
||||
else 校验失败
|
||||
L->>U : 显示校验提示
|
||||
end
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [frontend/src/views/Login.vue](file://frontend/src/views/Login.vue#L73-L89)
|
||||
- [frontend/src/stores/user.js](file://frontend/src/stores/user.js#L11-L20)
|
||||
|
||||
章节来源
|
||||
- [frontend/src/views/Login.vue](file://frontend/src/views/Login.vue#L1-L155)
|
||||
- [frontend/src/stores/user.js](file://frontend/src/stores/user.js#L1-L49)
|
||||
|
||||
### 仪表盘组件(Dashboard)
|
||||
- 角色定位
|
||||
- 容器组件:负责多维度数据加载、图表初始化与渲染、告警提示与表格展示。
|
||||
- 设计要点
|
||||
- 多个图表(趋势、饼图、科室排名、仪表盘)的初始化与响应式适配;计算属性用于派生指标;异常数据兜底。
|
||||
- 边界与接口
|
||||
- 输入:周期参数;输出:统计卡片、图表数据、告警集合。
|
||||
- 复用策略
|
||||
- 将图表配置与更新函数抽取为可复用的工具;对数据格式化与图表选项生成进行单元测试。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start(["进入 Dashboard"]) --> LoadStats["加载统计数据"]
|
||||
LoadStats --> LoadRanking["加载员工排名"]
|
||||
LoadRanking --> LoadTrend["加载趋势数据"]
|
||||
LoadTrend --> LoadDeptRanking["加载科室排名"]
|
||||
LoadDeptRanking --> LoadFinance["加载财务趋势"]
|
||||
LoadFinance --> LoadKpi["加载关键指标仪表盘"]
|
||||
LoadKpi --> InitCharts["初始化图表实例"]
|
||||
InitCharts --> RenderCharts["渲染图表与告警"]
|
||||
RenderCharts --> End(["完成渲染"])
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [frontend/src/views/Dashboard.vue](file://frontend/src/views/Dashboard.vue#L329-L422)
|
||||
- [frontend/src/views/Dashboard.vue](file://frontend/src/views/Dashboard.vue#L423-L448)
|
||||
|
||||
章节来源
|
||||
- [frontend/src/views/Dashboard.vue](file://frontend/src/views/Dashboard.vue#L1-L1082)
|
||||
|
||||
### 基础数据组件(Departments)
|
||||
- 角色定位
|
||||
- 容器组件:负责列表查询、分页、新增/编辑弹窗、状态切换与树形选择。
|
||||
- 设计要点
|
||||
- 搜索条件与分页参数传递至 API;树形选择使用树形数据;状态变更即时同步。
|
||||
- 边界与接口
|
||||
- 输入:搜索条件、分页参数;输出:表格数据、树形数据、提交结果。
|
||||
- 复用策略
|
||||
- 将 CRUD API 调用封装为独立函数;对表单校验与提交流程进行单元测试。
|
||||
|
||||
章节来源
|
||||
- [frontend/src/views/basic/Departments.vue](file://frontend/src/views/basic/Departments.vue#L1-L290)
|
||||
|
||||
### 考核管理组件(Assessments)
|
||||
- 角色定位
|
||||
- 容器组件:负责列表筛选、分页、批量创建、状态流转(提交/审核/确认)。
|
||||
- 设计要点
|
||||
- 多条件筛选与分页;批量创建弹窗;根据状态显示不同操作按钮。
|
||||
- 边界与接口
|
||||
- 输入:筛选条件、分页参数;输出:列表数据、批量创建结果。
|
||||
- 复用策略
|
||||
- 将状态标签映射与分数等级样式抽离为工具;对状态流转流程进行集成测试。
|
||||
|
||||
章节来源
|
||||
- [frontend/src/views/assessment/Assessments.vue](file://frontend/src/views/assessment/Assessments.vue#L1-L311)
|
||||
|
||||
### 考核详情组件(AssessmentDetail)
|
||||
- 角色定位
|
||||
- 容器组件:负责详情展示、草稿编辑、状态流转(保存/提交/审核/确认)。
|
||||
- 设计要点
|
||||
- 根据状态决定可编辑字段与操作按钮;状态标签与类型标签映射。
|
||||
- 边界与接口
|
||||
- 输入:路由参数(id);输出:详情数据、状态更新结果。
|
||||
- 复用策略
|
||||
- 将状态与类型映射封装为纯函数;对详情加载与状态更新进行单元测试。
|
||||
|
||||
章节来源
|
||||
- [frontend/src/views/assessment/AssessmentDetail.vue](file://frontend/src/views/assessment/AssessmentDetail.vue#L1-L257)
|
||||
|
||||
### 状态管理(Pinia Store)
|
||||
- 用户 Store(useUserStore)
|
||||
- 负责登录、获取用户信息、登出与 Token 管理;与路由联动。
|
||||
- 应用 Store(useAppStore)
|
||||
- 负责侧边栏折叠状态与科室树加载。
|
||||
- 导出聚合
|
||||
- 在 stores/index.js 中集中导出,便于视图组件按需引入。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class UserStore {
|
||||
+string token
|
||||
+object userInfo
|
||||
+login(username,password) Promise<bool>
|
||||
+getUserInfo() Promise<object>
|
||||
+logout() void
|
||||
}
|
||||
class AppStore {
|
||||
+boolean collapsed
|
||||
+array departmentTree
|
||||
+toggleSidebar() void
|
||||
+loadDepartmentTree() Promise<void>
|
||||
}
|
||||
class StoresIndex {
|
||||
+useUserStore()
|
||||
+useAppStore()
|
||||
}
|
||||
StoresIndex --> UserStore : "导出"
|
||||
StoresIndex --> AppStore : "导出"
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [frontend/src/stores/user.js](file://frontend/src/stores/user.js#L1-L49)
|
||||
- [frontend/src/stores/app.js](file://frontend/src/stores/app.js#L1-L31)
|
||||
- [frontend/src/stores/index.js](file://frontend/src/stores/index.js#L1-L3)
|
||||
|
||||
章节来源
|
||||
- [frontend/src/stores/user.js](file://frontend/src/stores/user.js#L1-L49)
|
||||
- [frontend/src/stores/app.js](file://frontend/src/stores/app.js#L1-L31)
|
||||
- [frontend/src/stores/index.js](file://frontend/src/stores/index.js#L1-L3)
|
||||
|
||||
### API 聚合与请求
|
||||
- API 聚合
|
||||
- 在 api/index.js 中统一导出各模块 API,便于视图组件按需引入。
|
||||
- 请求配置
|
||||
- Vite 开发服务器配置了 /api 代理到后端服务地址,便于前后端联调。
|
||||
|
||||
章节来源
|
||||
- [frontend/src/api/index.js](file://frontend/src/api/index.js#L1-L9)
|
||||
- [frontend/vite.config.js](file://frontend/vite.config.js#L14-L19)
|
||||
|
||||
## 依赖关系分析
|
||||
- 组件依赖
|
||||
- 视图组件依赖路由、状态与 API;布局组件依赖菜单 API 与用户/应用 Store。
|
||||
- 状态依赖
|
||||
- 用户 Store 与路由守卫配合实现鉴权;应用 Store 管理 UI 状态。
|
||||
- 外部依赖
|
||||
- Element Plus 提供图标、表单、表格、图表等 UI 能力;ECharts 用于可视化;Axios 用于网络请求。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
V_Login["Login.vue"] --> S_User["useUserStore"]
|
||||
V_Dash["Dashboard.vue"] --> API_Stats["stats API"]
|
||||
V_Dash --> ECharts["ECharts"]
|
||||
V_Dept["Departments.vue"] --> API_Dept["department API"]
|
||||
V_Asm["Assessments.vue"] --> API_Asm["assessment API"]
|
||||
V_AsmD["AssessmentDetail.vue"] --> API_Asm["assessment API"]
|
||||
Layout["Layout.vue"] --> S_App["useAppStore"]
|
||||
Layout --> API_Menu["menu API"]
|
||||
Main["main.js"] --> Router["router/index.js"]
|
||||
Main --> Stores["stores/*"]
|
||||
Main --> App["App.vue"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [frontend/src/views/Login.vue](file://frontend/src/views/Login.vue#L55-L89)
|
||||
- [frontend/src/views/Dashboard.vue](file://frontend/src/views/Dashboard.vue#L229-L231)
|
||||
- [frontend/src/views/basic/Departments.vue](file://frontend/src/views/basic/Departments.vue#L106-L106)
|
||||
- [frontend/src/views/assessment/Assessments.vue](file://frontend/src/views/assessment/Assessments.vue#L120-L122)
|
||||
- [frontend/src/views/assessment/AssessmentDetail.vue](file://frontend/src/views/assessment/AssessmentDetail.vue#L102-L102)
|
||||
- [frontend/src/views/Layout.vue](file://frontend/src/views/Layout.vue#L77-L81)
|
||||
- [frontend/src/main.js](file://frontend/src/main.js#L1-L24)
|
||||
|
||||
章节来源
|
||||
- [frontend/src/main.js](file://frontend/src/main.js#L1-L24)
|
||||
- [frontend/src/router/index.js](file://frontend/src/router/index.js#L1-L116)
|
||||
- [frontend/src/views/Layout.vue](file://frontend/src/views/Layout.vue#L1-L241)
|
||||
|
||||
## 性能考量
|
||||
- 路由懒加载
|
||||
- 路由组件使用动态导入,减少首屏体积,提升初始加载速度。
|
||||
- 图表性能
|
||||
- 仅在需要时初始化图表实例;监听窗口 resize 事件进行自适应;避免重复 setOption。
|
||||
- 状态缓存
|
||||
- 对于不频繁变化的数据(如菜单树、科室树)进行本地缓存,减少重复请求。
|
||||
- 交互反馈
|
||||
- 使用加载状态与防抖,避免频繁触发请求;对大列表使用分页与虚拟滚动(如后续扩展)。
|
||||
|
||||
章节来源
|
||||
- [frontend/src/router/index.js](file://frontend/src/router/index.js#L4-L96)
|
||||
- [frontend/src/views/Dashboard.vue](file://frontend/src/views/Dashboard.vue#L441-L448)
|
||||
|
||||
## 故障排查指南
|
||||
- 登录失败
|
||||
- 检查用户 Store 的登录返回值与错误处理;确认路由守卫是否正确拦截未登录访问。
|
||||
- 菜单加载失败
|
||||
- 检查菜单 API 返回结构与转换逻辑;确保降级菜单可用。
|
||||
- 图表空白或不更新
|
||||
- 检查图表实例是否初始化;确认数据源是否存在;验证 resize 事件绑定。
|
||||
- 鉴权失效
|
||||
- 检查本地 Token 是否存在;确认登出时是否清除 Token 并跳转登录。
|
||||
|
||||
章节来源
|
||||
- [frontend/src/views/Login.vue](file://frontend/src/views/Login.vue#L73-L89)
|
||||
- [frontend/src/views/Layout.vue](file://frontend/src/views/Layout.vue#L86-L116)
|
||||
- [frontend/src/views/Dashboard.vue](file://frontend/src/views/Dashboard.vue#L441-L448)
|
||||
- [frontend/src/stores/user.js](file://frontend/src/stores/user.js#L34-L39)
|
||||
|
||||
## 结论
|
||||
本项目在组件设计上体现了清晰的分层与职责划分:布局容器负责页面骨架与状态,业务视图承担数据与交互,Pinia 管理共享状态,API 聚合提供稳定接口。通过路由懒加载、图表性能优化与状态缓存等手段,兼顾了可维护性与用户体验。建议在后续迭代中进一步完善单元测试与集成测试,强化组件边界与接口契约,持续提升系统的稳定性与可扩展性。
|
||||
|
||||
## 附录
|
||||
- 组件拆分原则
|
||||
- 单一职责:每个组件只负责一个功能域内的展示与交互。
|
||||
- 高内聚:组件内部逻辑紧密相关,减少外部依赖。
|
||||
- 低耦合:通过明确的 props 与事件进行通信,避免直接依赖 DOM 或全局变量。
|
||||
- 容器与展示组件
|
||||
- 容器组件:负责数据加载、状态管理与流程控制;展示组件:负责具体 UI 渲染与用户交互。
|
||||
- 组件抽象与复用
|
||||
- 将通用逻辑(如表单校验、状态映射、图表配置)抽离为可复用函数或组合式工具。
|
||||
- 组件通信
|
||||
- 父子通信:通过 props 下传与 emits 上抛;兄弟通信:通过共同父组件或事件总线;跨级通信:通过事件总线或全局状态;事件总线:谨慎使用,建议优先选择 Pinia。
|
||||
- 状态管理
|
||||
- 局部状态:组件内部使用 ref/reactive;全局状态:Pinia Store;持久化:Token 存储于 localStorage。
|
||||
- 接口与边界
|
||||
- 明确输入输出类型;对异常情况进行降级处理;对外暴露稳定的 API 接口。
|
||||
- 测试策略
|
||||
- 单元测试:针对纯函数与组合式逻辑;集成测试:针对组件生命周期与交互流程;Mock 数据:使用静态 JSON 或模拟 API 返回。
|
||||
Reference in New Issue
Block a user