在中后台系统中,菜单模块往往涉及复杂的权限控制、流程状态驱动、模块适配等逻辑。本文结合真实开发实践,从配置结构设计 到状态响应式控制,构建出一套可扩展、高内聚的菜单系统。
📌 业务场景简介
假设我们有一个 Vue 项目中,存在多个模块(例如"管理端"、"用户端"),它们需要展示不同的功能菜单。同时,一些菜单项的显示还取决于全局状态(如某个流程是否已完成)或角色权限等。
❌ 常见做法(反面教材):
js
if (isAdmin) {
menuList.push({ title: '审批入口', show: true });
}
这种写法的问题:
- 👎 菜单定义散落在各处;
- 👎 难以统一维护顺序;
- 👎 与模块/状态强耦合,不利扩展。
✅ 第一阶段:菜单配置结构设计(Configuration-Driven)
我们首先将所有菜单项集中到一个配置列表中,并引入 variants
字段表示适用模块(或角色):
js
// constants/menu.js
const allMenus = [
{ title: '功能 A', href: 'featureA', icon: 'setting', show: true, variants: ['admin'] },
{ title: '功能 B', href: 'featureB', icon: 'user', show: true, variants: ['user'] },
{ title: '公共功能', href: 'common', icon: 'appstore', show: true },
];
export function getMenuByRole(role = 'user') {
return allMenus.filter(item => !item.variants || item.variants.includes(role));
}
在组件中使用:
js
const menuList = getMenuByRole('admin');
🎯 设计思想 1:配置驱动开发(Configuration over Code)
通过结构化数据控制 UI 行为,避免硬编码逻辑。
你不需要再写 if (role === 'admin')
来添加菜单,只需写一条配置。
✅ 第二阶段:菜单项状态控制(State-Driven)
除了模块角色,菜单展示还依赖全局状态,例如:
- "流程完成"后才展示"查看结果";
- "已提交"后才展示"审批记录"。
我们使用 Vuex 存储状态:
js
// store/index.js
state: {
workflowStatus: 'inReview', // 'done', 'pending'...
}
在组件中响应式控制:
js
computed: {
workflowStatus() {
return this.$store.state.workflowStatus;
}
},
watch: {
workflowStatus: {
handler(status) {
this.menuList = this.menuList.map(item => {
if (item.href === 'result') {
return { ...item, show: status === 'done' };
}
return item;
});
},
immediate: true,
}
}
🎯 设计思想 2:响应式编程(Reactive Programming)
你不是在命令式控制菜单项,而是让菜单展示成为 状态 => UI
的映射。
✅ 第三阶段:结构更新的正确方式
我们使用 .map()
返回新的菜单项列表,而不是直接修改原数组项:
js
this.menuList = this.menuList.map(item => {
if (item.href === 'result') {
return { ...item, show: true };
}
return item;
});
🎯 设计思想 3:不可变数据(Immutable Data)
- 保证响应式系统正确追踪变化;
- 避免副作用,利于调试和测试;
- 与函数式思想一致:函数输入输出明确,不修改外部状态。
🔍 深入分析:背后的设计模式
应用点 | 使用的设计模式或原则 | 解释 |
---|---|---|
variants 模块控制 |
✅ 策略模式(Strategy) | 菜单展示策略由模块名决定 |
watch workflowStatus |
✅ 观察者模式(Observer) | 状态变化触发 UI 更新 |
filter(item => ...) |
✅ 开放封闭原则(OCP) | 增加菜单项无需修改逻辑 |
配置统一集中管理 | ✅ 单一职责原则(SRP) | 菜单结构与展示逻辑分离 |
.map() 返回新数组 |
✅ 函数式编程思想 | 保持纯函数和数据不可变性 |
🧠 系统设计的提升点
- 结构清晰:菜单项一目了然,结构统一。
- 高扩展性:新增模块、角色、状态只需调整配置。
- 低耦合:菜单配置与业务逻辑解耦,利于重构。
- 响应驱动:状态变化自动驱动 UI,无需手动触发。
📦 可推广的应用场景
这套方案不仅适用于菜单:
- ✅ 表单项展示/禁用(根据流程或权限);
- ✅ 按钮权限(根据角色控制按钮是否展示);
- ✅ 工作流面板(根据阶段展示不同面板);
- ✅ 操作入口(如模块快捷操作区);
只要你遇到"多个 UI 元素是否展示依赖某些条件",都可以用这套方式统一解决。
✅ 总结
本次实战我们构建了一个:
- ✅ 模块化:不同模块菜单通过 variants 管理;
- ✅ 响应式:状态变动自动驱动菜单显示;
- ✅ 架构清晰:结构清晰、职责单一、便于维护;
- ✅ 设计模式合理:策略模式 + 观察者模式 + 函数式更新。
这不只是一个"菜单优化技巧",而是一套可以迁移到整个系统的可配置 + 状态驱动 + 响应式更新的架构思想。
📚 延伸阅读
📌 希望这篇文章能帮助你在项目中构建更清晰、更可维护的前端架构。如果你觉得有帮助,欢迎点赞 + 收藏 + 评论交流!