blur-admin 侧边栏导航组件 baSidebar 完全指南:手动配置与 ui-router 路由驱动的两级菜单体系
2026/9/23 20:09:29 网站建设 项目流程
  • 前端

【免费下载链接】blur-admin

AngularJS Bootstrap Admin Panel Framework

项目地址:https://gitcode.com/gh_mirrors/bl/blur-admin
点击查看免费下载

在 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)。此外,该指令还负责监听全局clickresize事件:当用户点击侧边栏外部、且当前菜单未折叠、又处于可隐藏视口时,会自动收起菜单;窗口尺寸变化时会重新计算菜单高度与折叠状态,并在$destroy时解绑事件,避免内存泄漏。

配置侧边栏菜单目前只支持 JavaScript 配置方式,具体有两条路线:

  • 手动配置:通过baSidebarServiceProvider.addStaticItem()在 Angular 的 configuration 块中注入静态菜单项;
  • 路由配置:在 ui-router 的 state 定义中携带sidebarMeta元数据,由侧边栏自动扫描并生成菜单项。

这两种方式可以同时使用(菜单项会合并显示),也可以只使用其中一种。

手动配置:addStaticItem 与菜单项属性

手动配置需要用到baSidebarServiceProvider,它暴露了addStaticItem方法,接收一个menuItem对象作为参数。该方法必须在 Angular 的 configuration 块(.config())中调用。

menuItem对象支持以下属性:

属性类型含义
titleString菜单项显示名称
iconString图标(CSS class 名),显示在标题旁边
stateRefString与该菜单项关联的 ui-router state 名称
fixedHrefString与该菜单项关联的 URL(与stateRef二选一,或按场景选用)
blankString是否在新浏览器标签页中打开上述 URL
subMenuArray 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.htmlreg.html404.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; }); }

可以提炼出三个关键机制:

  1. level由 state 名称中的点号数量推导:如charts有 0 个点,level = 0charts.amCharts有 1 个点,level = 1
  2. 父子归属通过 name 前缀匹配:在getMenuItems()中,先筛选出level == 0的菜单项,再为每个一级项收集level == 1name以该项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; });
  3. 排序规则是"先层级、后 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对象目前支持以下两个属性:

属性类型含义
iconString图标(CSS class 名),显示在标题旁边
orderNumber元素在当前层级中的排序序号

注意与手动配置的区别: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的分组容器。

实战小结:新增一个页面到侧边栏的最小步骤

  1. 在页面的.module.js中定义(或找到)对应的 ui-router state;
  2. 给 state 补充title属性作为菜单显示名;
  3. 添加sidebarMeta: { icon: '<图标类名>', order: <数字> }
  4. 若要挂在某个分组下,让 state 名称以该分组 state 名称开头(如charts.myChart),并确保分组 state 本身也有sidebarMeta
  5. 刷新页面,菜单项即自动出现在对应层级。

侧边栏的交互与响应式行为

除了菜单项的生成,仓库源码还揭示了侧边栏在交互与响应式方面的实现细节,理解这些有助于你在集成时预判其行为。

菜单折叠与隐藏的视口断点

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 天然绑定,新增页面只需声明titlesidebarMeta即可自动出现在导航中。理解level(由 state 名称点号推导)与order(同层排序)的配合规则、以及fixedHref/blank/disabled等菜单项属性的语义,是自由扩展 blur-admin 导航结构的关键。

  • 前端

【免费下载链接】blur-admin

AngularJS Bootstrap Admin Panel Framework

项目地址:https://gitcode.com/gh_mirrors/bl/blur-admin
点击查看免费下载

相关推荐

上一篇:终极Git仓库清理指南:bfg-repo-cleaner让大型项目管理更高效
下一篇:CATS智能减面教程:保留所有形状键的减面技巧

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询