
咱们直接开门见山。最近在做一个后台系统的界面整理登录之后右上角老是弹出一个站内消息的铃铛图标点击进去又没什么实际功能领导直接说“这玩意儿能不能去掉”。一开始以为是个小改动真要动起手来才发现里面水挺深。这篇就完整记录一下我这次的处理过程从定位代码到彻底隐藏再到只对指定角色显示把每一步的思路和踩过的坑都写清楚给同样在折腾这套界面的朋友做个参考。先说清楚前提我这里处理的“afc”是一个内部业务系统的代号登录方式走的是统一认证登录成功后系统会自动加载顶部导航栏消息图标就是导航栏右侧的那几个高频入口之一。这种布局在很多中后台系统里都很常见——左边菜单、面包屑、右上角放个人头像、消息提醒、退出按钮。如果你的系统结构类似那这篇文章的思路完全可以换壳复用。1. 需求分析与方案选型1.1 这个“消息图标”到底是谁渲染出来的很多新手上来就打开前端代码搜索“消息”“铃铛”这些关键词这种方法不能说错但容易绕远路。常见的情况是这个图标压根就不是业务页面自己写的而是框架自带的基础布局组件渲染的比如你们用的后台模板自带的一套layout消息提醒只是一个可配置的开关项目。我这次遇到的afc系统就是典型的自研前端框架整个顶部导航是动态拼接的消息图标的出现与否由后端返回的菜单配置控制。所以第一步先搞清楚它属于哪一种类型是写死在页面里的静态元素还是从接口动态渲染出来的。你可以用浏览器开发者工具直接右键那个图标选择“检查”先在元素面板看看它的DOM结构一般会带有醒目的id或者class比如header-msg、notification-badge这样的命名。看到这些特征基本就能判定这个是动态渲染的不适合用直接删代码这种暴力方式因为后续系统升级代码一合并又会被打回来。1.2 三种可行的隐藏思路对比针对这个需求市面上常见方案基本可以分成三种前端硬删、后端接口过滤、前端按角色条件渲染。第一种“前端硬删”最简单粗暴直接打开对应页面组件把那段渲染消息图标的模板代码删掉或者用CSS隐藏。优点是改起来快、效果直接缺点是系统一更新就失效而且所有用户都不显示了哪怕你以后想让管理员看到这个入口也得重新改回来属于一把梭但后患无穷。第二种“后端接口过滤”是指修改生成顶部导航菜单的后端接口把消息图标的配置项从返回值里剔除。这种方案生效范围广前后端都干净但如果你没有后端代码的修改权限或者只拿到一个发布包那就完全不适用。第三种“前端按角色条件渲染”是保留这个入口的配置能力在渲染时根据当前登录用户的权限角色去判断只有指定角色才显示。这种做法最灵活也最接近真实业务需求——通常领导不要这个图标不代表运维也不需要真正合理的需求往往是“不是所有人都要看得到”。我把三种方案的适应场景和优缺点放在一起对比你自己判断该选哪条路。方案改动范围是否按角色控制升级影响建议场景前端硬删/CSS隐藏前端视图层否系统升级易回归临时应急、快速看效果后端菜单接口过滤前后端联动是需同时改两处有完整代码权限、追求干净前端角色条件渲染前端逻辑是仅前端变更、相对可控多角色共存、细粒度控制1.3 我为什么最后选了“前端角色条件渲染”因为手里这套afc系统是整个团队在维护不是我一个人的实验田。直接硬删一时爽下次别人拉代码的时候如果有冲突排查起来想死的心都有。而且需求方的原话是“登录后不要显示”但没说“所有登录用户都不显示”这意味着很可能还有一部分角色将来要用这个入口来看待办审批。果然在梳理权限矩阵的时候发现至少有三个项目经理账号是需要收消息提醒的他们每天靠这个图标有没有红点来判断有没有新的审批单进来。这种情况下如果当初图省事直接删掉那几个项目经理就得一天到晚刷新页面检查审批列表工作体验直接倒退十年。所以最终的方案锁定了前端模板里加一个角色判断满足条件才显示否则不渲染这个DOM节点。2. 核心细节解析与实操要点2.1 定位图标对应的代码位置这一步是整个改动里最花时间的地方因为afc的前端项目结构比较老没有完全组件化顶部导航的模板是几个文件拼在一起的。我建议先从页面源码入手在浏览器里用开发者工具选中图标元素看到它所在的整个导航栏容器是什么组件再去代码仓库里搜索这个组件的文件路径。我当时顺着DOM结构找到了一个header.js文件它导出一个配置数组数组里每一项代表顶部导航的一个按钮包括图标名称、跳转链接、是否显示小红点等字段。消息图标在这一项的配置大概是{ id: message, icon: bell-outline, text: 站内消息, show: true, showBadge: true, roles: [admin], // 预计控制角色 }这类配置文件一般会由一个循环渲染遍历整个数组逐个输出导航项。那么我们改动的关键就落在这个数组的过滤逻辑上而不是去改某个单独页面的视觉层。2.2 消息图标隐藏的前置条件检查动手之前想清楚几件事否则很容易改完一脸懵当前账号是否有测试权限是否能看到这个图标有的系统会按环境变量区分生产环境和测试环境的菜单配置不同别改了半天发现本地根本复现不出来。消息图标的红点数字是怎么来的一般有两种来源一种是用轮询接口去查未读消息数另一种是WebSocket推送。如果你只是不加role判断那就算图标隐藏了浏览器控制台里依然会不停发请求这个问题后面专门说。是否所有角色共享同一个导航模板有的系统会为不同角色配不同的导航模板文件那样的改动点就不是判断而是直接选模板了要先去路由配置里看看当前登录用户的模板归属。我把这些前置项截图收集起来发给团队另一个同事复核确认信息的完整性避免自己推导出来的条件有遗漏。这个过程看似简单但很多人就是省了这一步结果改完角色判断之后反而把系统原有的逻辑搞乱了。2.3 权限角色体系怎么查如果你对这套系统的权限体系不熟第一步别急着改代码先找到当前登录用户的角色标识。afc系统的用户信息存在全局状态里我在控制台里执行一条语句就能看到登录后的用户对象// 示例在控制台查看当前用户信息 console.log(window.currentUser); // 输出中会有 roleId / roleName / isAdmin 这类字段拿到字段名之后再去查权限路由表看看这个字段的值都有哪些枚举比如1代表管理员2代表项目经理3代表普通成员。这一步拿到之后才能决定角色判断到底怎么写。另外要留意一个常见坑很多系统的角色字段不是单值而是一个数组。比如用户同时是“项目经理”和“审计员”那么判断时就不能直接比较而是要用includes方法去看数组里是否包含目标角色ID。2.4 为什么用角色判断而不是用户ID判断你可能想问直接判断当前登录用户名不就行了何必绕一圈去写角色呢。道理其实很简单用户ID是离散的今天你能列出三五个明天业务一变化又多出几个新账号你还得回头改代码。角色是收敛的你要控制的就那么几个固定身份。在业务系统里凡是面向管理需求的展示控制几乎都是围绕角色权限做的这一点在afc系统里也很一致。3. 完整实操过程与配置示例3.1 环境准备与前期排查我这次的工程环境是前后端分离前端是Vue 2.7 Webpack 的老项目后端是Java接口。前端仓库拉下来之后先安装依赖跑起来连接测试环境联调这样改了页面效果能及时看到。打开开发者工具切到Network面板刷新页面后重点看菜单相关的请求。afc系统里这个接口路径大概是/api/menu/topbar返回的数据结构类似{ code: 0, data: [ { id: message, icon: bell-outline, text: 站内消息, order: 4 }, { id: profile, icon: account-circle, text: 个人中心, order: 5 } ] }到这里我们能确定一件事后端确实把菜单配置做成动态数据供前端消费但前端也不完全是盲目的照单全收很多展示逻辑还是在自己模板里控制。比如我们最终要增加的角色判断本质是在前端消费数据时提前做一次过滤。3.2 后端接口过滤的完整改法如果带着后端权限我建议直接把这一步做干净。在返回菜单配置的Java类里根据当前登录用户的角色类型把消息菜单的visible字段设为false这样前端拿到的数据里压根就没有这个菜单项自然全站统一隐藏。// 伪代码示意 if (!currentUser.hasRole(BaseRoleManager.PROJECT_MANAGER)) { topBarItems.removeIf(item - message.equals(item.getId())); }这样改的优点是彻底既不需要前端每个渲染位置都考虑也能彻底关掉图标和红点数字的来源。缺点也明显如果后端代码不在你手里或者你只有前端发布权限这条路线就走不通。3.3 前端条件渲染的具体写法最终实际采用的方案还是前端的角色控制因为改起来快速、影响范围清晰可回退。实现思路就一句话在顶部导航渲染循环里遍历到那个消息按钮时再额外做一次角色校验。我在header.js里定义了一个工具函数// 判断当前用户角色是否在白名单内 function isRoleAllowed(allowedRoles) { const currentUser getCurrentUser(); if (!currentUser || !Array.isArray(currentUser.roles)) return false; return currentUser.roles.some(role allowedRoles.includes(role)); }然后在模板渲染部分通过v-if做判定template v-foritem in topBarItems div v-if!item.onlyShowRoles || isRoleAllowed(item.onlyShowRoles) :keyitem.id classtopbar-item i :classitem.icon/i span v-ifitem.showBadge classbadge{{ item.badgeCount }}/span /div /template其中onlyShowRoles是一个可选配置我们给消息按钮加上这个字段{ id: message, icon: bell-outline, text: 站内消息, showBadge: true, onlyShowRoles: [project_manager], // 只给项目经理角色看 }这样普通用户登录后这个按钮连DOM都不会渲染出来红点更不可能出现。而项目经理账号登录时它照常显示红点数字还是正常推。3.4 参数与逻辑详解这里有一个容易被忽略的点v-if判断的时机。当用户信息还在异步加载时currentUser是空的isRoleAllowed会返回false导致就算是有权限的角色首次渲染也会一闪而过地隐藏图标等到用户信息到位之后又突然冒出来。我这次没有直接踩这个坑以前在另一个项目里遇到过出现了明显的闪烁动画极其难受。所以这次特意做了处理在用户信息加载完成之前整个顶部导航干脆先不渲染等数据回来之后一次性渲染出来这样从视觉效果上就不会出现先隐藏后显示的情况写一个v-loading或者v-ifisUserLoaded包住顶栏即可。另外红点数字的轮询请求也要同步关掉否则虽然图标不显示了后台还在跑着未读消息的轮询白白消耗接口资源。最好的方式是在消息按钮隐藏的时候不去注册这个轮询任务。我们是把消息轮询和消息按钮的渲染绑定在一起的图标存在才开启轮询图标不需要显示就不创建定时器两行代码的改动但省了很多不必要的请求。4. 常见问题与排查技巧实录4.1 图标还是顽强地显示如果你加了v-if判断刷新之后发现图标还在这时候别急着怀疑代码没生效。先梳理一下几个最常出现的问题你是不是改了生产环境代码而测试环境有缓存我就干过这事以为没生效结果过了半天才发现环境连错了。浏览器缓存是不是旧的Bundle打包后的文件如果带了hash一般不会缓存出问题但如果开发环境的配置不规范真会被缓存坑到。我的习惯是改完代码先强制刷新一次再不行就开无痕窗口验证。有没有全局组件拦截了你的判断比如有的项目会封装一个导航组件内部又用了一套自己的配置跳过了外层判断导致你在入口处加的条件完全没走到。你判断的角色字段是不是拿错了在控制台打印用户对象确认角色字段是在roles数组里还是直接挂在role字段上这一条看着基础理论上最容易踩。4.2 隐藏图标后红点数字还在跳这属于隐藏不彻底。图标本身是通过v-if控制不渲染了但轮询函数还在消息数量还在实时更新。一个比较隐蔽的问题是如果项目里用了状态管理库比如Vuex那个未读数量存在全局Store里社区版或者老版本里不会因为你隐藏了图标就自动停止更新。解决办法有两个方向。简单的方式是在消息按钮的渲染条件为false的时候直接不去执行获取未读数量的接口复杂一点的方向是把轮询任务在用户角色不匹配时主动清理掉在路由守卫里做周期任务的中断判断。前者改动小适合快速拿结果后者更适合大型长期项目。4.3 其他用户的界面被误伤经常会遇到一种情况你测试时用管理员账号登录一切正常但你同事用普通账号登录发现原本应该保留的其他导航项也不见了。原因基本出在过滤逻辑写成了“白名单全量校验”而不是“单项过滤”。比如你可能写成了v-for循环时先过滤item.roles那么如果一个导航项没有配置roles字段就会被当成没有权限的用户直接丢弃但很多导航项是“所有登录用户都能看到”的。正确做法是判断策略选择“有才拦、无则放”也就是// 错误的思路 if (item.roles.includes(user.role)) { render } // 正确的思路 if (!item.roles || item.roles.includes(user.role)) { render }默认不配置roles的菜单项应该属于通用菜单只有明确配置了限制角色的菜单才做拦截这样才不会误伤公共入口。4.4 样式错乱与位置偏移图标隐藏后原本的位置被腾了出来这个问题偶尔会带来相邻元素错位。其实多数框架都会有flex布局或者栅格系统少一项顶多就是空出一个位置但个别老项目写的是绝对定位一隐藏就可能导致头像位置跑偏。如果遇到这种情况第一反应不是去调布局而是先把原来的图标位置占位符去掉确认其他元素是自然流排列。实在不行就保留一个宽度为0且不可见的元素占住原来的位置确保整体视觉不跳动。但这是下下策能不用就别用。4.5 后续扩展的建议如果你这次的目的是让“站内消息”这个功能离开主视觉而不是彻底下线那我建议在个人中心或者侧边栏里保留一个静态入口这样想用的人还能找到不至于功能完全封闭。我有一次就是因为直接把图标封掉结果有同事反馈一直收不到审批通知后来在个人中心加了一个带红点的列表入口才算解决。根据我个人实际改完这套afc系统的经验最大的体会是界面上的每个元素看起来是个简单控件背后往往连着权限、配置、数据流一轮完整链路。直接删掉代码是最容易的但也是最容易给自己挖坑的。多花半小时想一想“这个按钮为什么会出现在这里它被谁使用它背后跑了什么请求”改完之后的效果才真正稳妥。