- 前端
【免费下载链接】blur-admin
AngularJS Bootstrap Admin Panel Framework
在 blur-admin(AngularJS Bootstrap Admin Panel Framework)这类后台管理框架中,侧边栏(Sidebar)是承担全局导航的核心组件。本文以仓库文档 docs/contents/articles/051-sidebar/index.md 为主体,结合src/app/theme/components/baSidebar/目录下的指令、控制器、服务与模板源码,系统讲解baSidebar指令的用法、两种配置方式(手动配置与 ui-router 路由配置)的完整参数语义、菜单的分层分组与排序原理,以及折叠/隐藏等交互行为,帮助你为新增页面快速接入侧边栏导航。
侧边栏是什么:单例式的导航组件
Sidebar 用于为应用提供便捷的导航方式。按官方文档的定位,它有几个关键约束:
- 每个 Angular 应用只支持一个侧边栏,也就是说,Sidebar 本质上是一个单例对象;
- 当前支持一级(level 1)和二级(level 2)子菜单;
- 它通过
baSidebar指令创建,最小用法只需一行 HTML:
<ba-sidebar></ba-sidebar>从源码看,该指令定义在 baSidebar.directive.js 中,声明为元素型指令(restrict: 'E'),模板指向 ba-sidebar.html,控制器为BaSidebarCtrl(见 BaSidebarCtrl.js)。此外,该指令还负责监听全局click与resize事件:当用户点击侧边栏外部、且当前菜单未折叠、又处于可隐藏视口时,会自动收起菜单;窗口尺寸变化时会重新计算菜单高度与折叠状态,并在$destroy时解绑事件,避免内存泄漏。
配置侧边栏菜单目前只支持 JavaScript 配置方式,具体有两条路线:
- 手动配置:通过
baSidebarServiceProvider.addStaticItem()在 Angular 的 configuration 块中注入静态菜单项; - 路由配置:在 ui-router 的 state 定义中携带
sidebarMeta元数据,由侧边栏自动扫描并生成菜单项。
这两种方式可以同时使用(菜单项会合并显示),也可以只使用其中一种。
手动配置:addStaticItem 与菜单项属性
手动配置需要用到baSidebarServiceProvider,它暴露了addStaticItem方法,接收一个menuItem对象作为参数。该方法必须在 Angular 的 configuration 块(.config())中调用。
menuItem对象支持以下属性:
| 属性 | 类型 | 含义 |
|---|---|---|
title | String | 菜单项显示名称 |
icon | String | 图标(CSS class 名),显示在标题旁边 |
stateRef | String | 与该菜单项关联的 ui-router state 名称 |
fixedHref | String | 与该菜单项关联的 URL(与stateRef二选一,或按场景选用) |
blank | String | 是否在新浏览器标签页中打开上述 URL |
subMenu | Array of menu items | 作为下一级子菜单显示的菜单项列表 |
文档给出的最小示例:
baSidebarServiceProvider.addStaticItem({ title: 'Menu Level 1', icon: 'ion-ios-more' });再看服务实现 baSidebar.service.js,addStaticItem会把传入的参数逐个追加进内部数组staticMenuItems:
var staticMenuItems = []; this.addStaticItem = function() { staticMenuItems.push.apply(staticMenuItems, arguments); };最终在getMenuItems()中,手动配置的静态项会拼接在由路由状态生成的菜单项之后:return menuItems.concat(staticMenuItems);。
仓库内真实的手动配置示例
pages.module.js 的routeConfig里给出了非常完整的手动配置实战范例,几乎用到了menuItem的全部属性:
function routeConfig($urlRouterProvider, baSidebarServiceProvider) { $urlRouterProvider.otherwise('/dashboard'); baSidebarServiceProvider.addStaticItem({ title: 'Pages', icon: 'ion-document', subMenu: [{ title: 'Sign In', fixedHref: 'auth.html', blank: true }, { title: 'Sign Up', fixedHref: 'reg.html', blank: true }, { title: 'User Profile', stateRef: 'profile' }, { title: '404 Page', fixedHref: '404.html', blank: true }] }); baSidebarServiceProvider.addStaticItem({ title: 'Menu Level 1', icon: 'ion-ios-more', subMenu: [{ title: 'Menu Level 1.1', disabled: true }, { title: 'Menu Level 1.2', subMenu: [{ title: 'Menu Level 1.2.1', disabled: true }] }] }); }这个例子透露了几个在文档基础上更进一步的实战细节:
fixedHref+blank组合:用于把站外页面(这里是auth.html、reg.html、404.html)以新标签页方式打开;从 ba-sidebar.html 模板可见,blank会渲染为target="_blank";stateRef单独使用:User Profile直接绑定 ui-router 的profilestate,通过ui-state指令完成跳转;disabled属性:虽然不在文档的参数表中,但模板专门为其提供了渲染分支——禁用项渲染为不可点击的纯文本链接,常用于占位或演示分级菜单(Menu Level 1.2.1即三层嵌套的演示项);- 手动配置同样支持多级嵌套
subMenu,模板对第三层子菜单也有对应的渲染逻辑。
路由配置:sidebarMeta 驱动的菜单自动生成
路由配置是另一种(也是框架主推的)方式。默认情况下,侧边栏会遍历应用中定义的所有 ui-router state,逐一检查其中是否存在sidebarMeta对象;只要某个 state 携带该属性,就会据此生成一个菜单项。
层级分组原理
state 会按照层级被分组:如果某个 state 存在父级 abstract state,并且二者都定义了sidebarMeta,那么子 state 就会作为父级菜单项的子项展示。
这个"父子关系"在服务层有非常清晰的实现逻辑(baSidebar.service.js 的defineMenuItemStates):
function defineMenuItemStates() { return $state.get() .filter(function(s) { return s.sidebarMeta; }) .map(function(s) { var meta = s.sidebarMeta; return { name: s.name, title: s.title, level: (s.name.match(/\./g) || []).length, order: meta.order, icon: meta.icon, stateRef: s.name, }; }) .sort(function(a, b) { return (a.level - b.level) * 100 + a.order - b.order; }); }可以提炼出三个关键机制:
level由 state 名称中的点号数量推导:如charts有 0 个点,level = 0;charts.amCharts有 1 个点,level = 1;- 父子归属通过 name 前缀匹配:在
getMenuItems()中,先筛选出level == 0的菜单项,再为每个一级项收集level == 1且name以该项name开头的 state 作为subMenu:menuItems.forEach(function(item) { var children = states.filter(function(child) { return child.level == 1 && child.name.indexOf(item.name) === 0; }); item.subMenu = children.length ? children : null; }); - 排序规则是"先层级、后 order":
(level差) * 100 + order差意味着不同层级之间永远先按层级排,同层级内才按order数值升序排列。
菜单项名称来源
菜单项的名称取自 state 的title属性(注意不是name)。文档给出的标准示例:
$stateProvider .state('dashboard', { url: '/dashboard', templateUrl: 'app/pages/dashboard/dashboard.html', title: 'Dashboard', sidebarMeta: { icon: 'ion-android-home', order: 0, }, });sidebarMeta 支持的属性
sidebarMeta对象目前支持以下两个属性:
| 属性 | 类型 | 含义 |
|---|---|---|
icon | String | 图标(CSS class 名),显示在标题旁边 |
order | Number | 元素在当前层级中的排序序号 |
注意与手动配置的区别:title不写在sidebarMeta里,而是直接取 state 自身的title;跳转目标也不需要配置——它就是 state 本身(stateRef: s.name)。
仓库中的路由配置实战盘点
仓库各功能模块的.module.js文件里散布着大量sidebarMeta用例,可以直接对照学习:
父级抽象 state + 子 state 的经典模式(charts.module.js):
.state('charts', { url: '/charts', abstract: true, template: '<div ui-view autoscroll="true" autoscroll-body-top></div>', title: 'Charts', sidebarMeta: { icon: 'ion-stats-bars', order: 150, }, });其子级分别定义了order: 0(amCharts,amCharts.module.js)、order: 100(Chartist,chartist.module.js)、order: 200(Chart.js,chartJs.module.js)、order: 300(Morris,morris.module.js)。由于 state 名称都形如charts.xxx,它们会自动挂到charts菜单项下,并严格按 order 升序显示。
Maps 模块(maps.module.js)同样展示了这种结构:父级maps使用ion-ios-location-outline图标、order: 500,四个子地图页gmap(0)、leaflet(100)、bubble(200)、line(300)依次排列。
表单模块(见 form.module.js 附近的路由定义)则演示了"同一父级下多个子 state 排序"的常见写法:form.inputs(order 0)、form.layouts(order 100)、form.wizard(order 200)。
组件模块(components.module.js)和 Timeline(timeline.module.js)分别展示了components父级与components.timeline子级带独立图标的组合。邮件模块(mail.module.js)甚至允许abstract的中间 state(components.mail)也声明sidebarMeta,成为下一级components.mail.label的分组容器。
实战小结:新增一个页面到侧边栏的最小步骤
- 在页面的
.module.js中定义(或找到)对应的 ui-router state; - 给 state 补充
title属性作为菜单显示名; - 添加
sidebarMeta: { icon: '<图标类名>', order: <数字> }; - 若要挂在某个分组下,让 state 名称以该分组 state 名称开头(如
charts.myChart),并确保分组 state 本身也有sidebarMeta; - 刷新页面,菜单项即自动出现在对应层级。
侧边栏的交互与响应式行为
除了菜单项的生成,仓库源码还揭示了侧边栏在交互与响应式方面的实现细节,理解这些有助于你在集成时预判其行为。
菜单折叠与隐藏的视口断点
layoutSizes常量定义在 theme.constants.js:
.constant('layoutSizes', { resWidthCollapseSidebar: 1200, resWidthHideSidebar: 500 })对应 baSidebar.service.js 中的两个判定方法:
function shouldMenuBeCollapsed() { return window.innerWidth <= layoutSizes.resWidthCollapseSidebar; } function canSidebarBeHidden() { return window.innerWidth <= layoutSizes.resWidthHideSidebar; }也就是说:窗口宽度≤ 1200px时菜单默认折叠为图标模式;≤ 500px时侧边栏可以被完全隐藏。baSidebar指令在窗口resize时自动调用这两个方法同步状态;BaSidebarCtrl则在每次$stateChangeSuccess(路由切换成功)后,若当前视口允许隐藏则自动收起菜单。
子菜单展开/折叠与悬停指示
baSidebarHelpers.directive.js 实现了一组配套辅助指令:
baSidebarToggleMenu/baSidebarCollapseMenu:分别用于整体展开、收起菜单,点击时会标记事件已处理($sidebarEventProcessed),避免触发指令外层"点击外部收起菜单"的逻辑;baUiSrefToggler:点击带子菜单的项时切换展开状态;若整个侧边栏处于折叠态,会先展开侧边栏再展开子菜单(移动端除外,移动端侧边栏应完全隐藏);baUiSrefTogglingSubmenu:实际通过slideDown()/slideUp()动画展开/收起子菜单;- 路由进入某个子菜单对应的 state 时,对应父项会自动展开并高亮(基于
ui-sref-active="selected"与$stateChangeStart/$stateChangeSuccess监听)。
此外,BaSidebarCtrl.js 中的hoverItem会计算悬浮项的位置与高度,配合模板末尾的sidebar-hover-elem元素实现菜单项上的高亮指示条效果;模板 ba-sidebar.html 还支持触摸手势:右滑展开、左滑收起(ng-swipe-right/ng-swipe-left)。
相关源码文件索引
| 作用 | 文件 |
|---|---|
| 侧边栏指令(事件绑定、菜单高度计算) | baSidebar.directive.js |
| 侧边栏控制器(菜单项、悬停指示、路由切换收起) | BaSidebarCtrl.js |
侧边栏服务 Provider(addStaticItem、菜单聚合与排序、折叠判定) | baSidebar.service.js |
侧边栏 HTML 模板(两级/三级菜单渲染、fixedHref/blank/disabled处理) | ba-sidebar.html |
展开/折叠辅助指令(baUiSrefToggler等) | baSidebarHelpers.directive.js |
| 视口断点常量(1200 / 500) | theme.constants.js |
| 手动配置示例(Pages 菜单、Menu Level 1 演示) | pages.module.js |
| 路由配置示例(图表、地图、表单、组件模块) | charts.module.js、maps.module.js、form.module.js 等 |
总结
blur-admin 的侧边栏通过baSidebar指令 +baSidebarService服务实现了一套灵活的单例导航体系:手动配置适合放置与路由无关的静态链接(如站外页面、演示占位项),路由配置则让菜单与页面 state 天然绑定,新增页面只需声明title与sidebarMeta即可自动出现在导航中。理解level(由 state 名称点号推导)与order(同层排序)的配合规则、以及fixedHref/blank/disabled等菜单项属性的语义,是自由扩展 blur-admin 导航结构的关键。
- 前端
【免费下载链接】blur-admin
AngularJS Bootstrap Admin Panel Framework
相关推荐
react-admin ra-navigation 的 IconMenu 图标菜单组件:极简侧边栏与多级导航实战指南
react admin ra navigation 的 IconMenu 图标菜单组件:极简侧边栏与多级导航实战指南 本篇技术指南围绕 react admin
前端UI组件Element UI 导航菜单(NavMenu)完全指南:顶栏、侧栏、折叠与 Vue Router 集成实践
Element UI 导航菜单(NavMenu)完全指南:顶栏、侧栏、折叠与 Vue Router 集成实践 Element UI 的 NavMenu 导航菜单
前端UI组件设计系统BlurAdmin侧边栏配置全攻略:手动与路由两种实现方式对比
BlurAdmin侧边栏配置全攻略:手动与路由两种实现方式对比 你是否还在为管理系统的侧边栏配置感到困惑?是否想知道如何快速实现动态导航菜单?本文将详细对比Bl
前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考