读源码 | metisMenu侧边栏插件
—————————————————————————————————————————————————————————
使用方法
实现效果
引入文件
<link rel="stylesheet" href="vendor/bootstrap/css/bootstrap.css"> // bootstrap样式
<link href="vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css"> // 图标使用font-awesome
<link rel="stylesheet" href="vendor/metisMenu/metisMenu.css"> // 插件样式
<script src="vendor/jquery/jquery.js"></script> // 基于jquery实现
<script src="vendor/bootstrap/js/bootstrap.min.js"></script> // 使用bootstrap的collapse插件
<script src="vendor/metisMenu/metisMenu.min.js"></script> // 插件代码
调用方法
<script type="text/javascript"> $(function() { $('#side-menu').metisMenu(); // ul.nav#side-menu }) </script>
使用样例
<<Demo.html>>
<nav class="navbar navbar-default navbar-static-top"> <div class="navbar-default sidebar" role="navigation"> <div class="sidebar-nav navbar-collapse"> <ul class="nav" id="side-menu"> <li class="sidebar-search"> <div class="input-group custom-search-form"> <input type="text" class="form-control" placeholder="Search..."> <span class="input-group-btn"> <button class="btn btn-default" type="button"> <i class="fa fa-search"></i> </button> </span> </div> </li> <li> <a href=""><i class="fa fa-dashboard fa-fw"></i> Dashboard</a> </li> <li> <a href="#"><i class="fa fa-bar-chart-o fa-fw"></i> Charts<span class="fa arrow"></span></a> <ul class="nav nav-second-level"> <li> <a href="">Flot Charts</a> </li> <li> <a href="">Morris.js Charts</a> </li> </ul> </li> <li> <a href=""><i class="fa fa-table fa-fw"></i> Tables</a> </li> <li> <a href=""><i class="fa fa-edit fa-fw"></i> Forms</a> </li> <li> <a href="#"><i class="fa fa-wrench fa-fw"></i> UI Elements<span class="fa arrow"></span></a> <ul class="nav nav-second-level"> <li> <a href="">Panels and Wells</a> </li> <li> <a href="">Buttons</a> </li> <li> <a href="">Notifications</a> </li> <li> <a href="">Typography</a> </li> <li> <a href=""> Icons</a> </li> <li> <a href="">Grid</a> </li> </ul> </li> <li> <a href="#"><i class="fa fa-sitemap fa-fw"></i> Multi-Level Dropdown<span class="fa arrow"></span></a> <ul class="nav nav-second-level"> <li> <a href="#">Second Level Item</a> </li> <li> <a href="#">Second Level Item</a> </li> <li> <a href="#">Third Level <span class="fa arrow"></span></a> <ul class="nav nav-third-level"> <li> <a href="#">Third Level Item</a> </li> <li> <a href="#">Third Level Item</a> </li> <li> <a href="#">Third Level Item</a> </li> <li> <a href="#">Third Level Item</a> </li> </ul> </li> </ul> </li> <li class="active"> <a href="#"><i class="fa fa-files-o fa-fw"></i> Sample Pages<span class="fa arrow"></span></a> <ul class="nav nav-second-level"> <li> <a class="active" href="#">Blank Page</a> </li> <li> <a href="#">Login Page</a> </li> </ul> </li> </ul> </div> </div> </nav>
<<blank.css>>
@media (min-width: 768px) { .sidebar {position: absolute;width: 250px;margin-top: 51px;z-index: 2;} } .sidebar .sidebar-search {padding: 15px;} .sidebar ul li a.active {background-color: #eee;} .sidebar ul li {background: #f8f8f8;border-bottom: #e7e7e7 1px solid;} .nav-second-level li {border-bottom: 0 !important;} .nav-second-level li a {padding-left: 38px;}
树形图
p.s.自定义样式用下划线表示
—————————————————————————————————————————————————————————
源码解读
调用
使用$.fn.extend(object)的方式为jquery类添加成员方法,功能封装在原型中,能够全局调用;
通过$("#side-menu")生成的jquery类实例来调用该方法;
初始配置
全局定义插件名称pluginName,定义对象defaults存放toggle(展开/闭合)与doubleTapToGo(双击事件)的开关;
样式
使用font-awesome来扩展侧边栏图标和展开标识(三角),引入font-awesome.css后只需要通过i.fa.fa-***来调用就可以了
基础布局通过bootstrap类实现,详细分支情况见属性图
初始化展开
借助bootstrap内置的collapse插件来实现;
通过检测<li.active>来标识当前页对应的列表,在metisMenu.js中检查是否需要展开的列表;
判断激活的标签栏是否有子列表,如果有则添加.collapse.in类(bootstrap.css),实际为添加样式{display:block};
未被激活的标签栏如果有子列表则添加.collapse类(boostrap.css),{display:none};
监听点击事件
监听方法借助bootstrap的collapse插件;
绑定事件时需要遵循collapse插件规则.on("click"+"."+pluginName,function(e){});
为点击的标签栏添加激活样式.active,如果有子列表则展开/关闭,使用collapse插件方法.collapse("toggle");
闭合其他所有有子列表的标签栏,使用.collapse("hide");
—————————————————————————————————————————————————————————
简单版 v1.0
功能
仅实现基础效果
复写代码
<<metisMenu-demo1.js>>
/** * Created by hughd on 2017/8/9. * 简单版 - v1.0 * 仅实现基础折叠 */ ;(function ($, window, document, undefined) { var pluginName = "metisMenu"; var toggle = true; function Plugin(element, options) { this.element = $(element); this.init(); } Plugin.prototype = { init: function () { var $this = this.element; // var obj = this; $this.find("li.active").has("ul").children("ul").addClass('collapse in');// 初始激活的元素的后代全部展开 $this.find('li').not(".active").has("ul").children("ul").addClass('collapse');// 未激活的元素显示隐藏 // 监听点击事件 $this.find("li").children("a").on("click." + pluginName, function () { //被点击的元素激活样式并展开 $(this).parent('li').toggleClass('active').children("ul").collapse("toggle"); if (toggle) { //将其他被展开的元素闭合 $(this).parent("li").siblings().removeClass("active").children("ul").collapse("hide"); } }); } } $.fn[pluginName] = function (options) { // 实例化Plugin对象,并存放在元素<ul#side-menu>._proto_.metisMenu中 this.data(pluginName, new Plugin(this, options)); return this; } })(jQuery, window, document);
实现思路
-
初始化
获取当前激活的标签,将该标签的内容显示(如果没有子标签则不显示)
未激活的标签,所有子列表隐藏
-
点击事件(通过boostrap的collapse插件)
当前点击的标签获取激活样式,子列表展开
除点击标签之外的其他标签移除激活样式,并闭合
—————————————————————————————————————————————————————————
完整插件
功能
IE浏览器兼容情况;
移除已有metisMenu数据情况
双击标题事件
源码
<<metisMenu.js>>
/* * metismenu - v1.1.3 * Easy menu jQuery plugin for Twitter Bootstrap 3 * https://github.com/onokumus/metisMenu * * Made by Osman Nuri Okumus * Under MIT License */ ;(function($, window, document, undefined) { var pluginName = "metisMenu", defaults = { toggle: true, doubleTapToGo: false }; function Plugin(element, options) { this.element = $(element); this.settings = $.extend({}, defaults, options); this._defaults = defaults; this._name = pluginName; this.init(); } Plugin.prototype = { init: function() { var $this = this.element, $toggle = this.settings.toggle, obj = this; if (this.isIE() <= 9) { $this.find("li.active").has("ul").children("ul").collapse("show"); $this.find("li").not(".active").has("ul").children("ul").collapse("hide"); } else { $this.find("li.active").has("ul").children("ul").addClass("collapse in"); $this.find("li").not(".active").has("ul").children("ul").addClass("collapse"); } //add the "doubleTapToGo" class to active items if needed if (obj.settings.doubleTapToGo) { $this.find("li.active").has("ul").children("a").addClass("doubleTapToGo"); } $this.find("li").has("ul").children("a").on("click" + "." + pluginName, function(e) { e.preventDefault(); //Do we need to enable the double tap if (obj.settings.doubleTapToGo) { //if we hit a second time on the link and the href is valid, navigate to that url if (obj.doubleTapToGo($(this)) && $(this).attr("href") !== "#" && $(this).attr("href") !== "") { e.stopPropagation(); document.location = $(this).attr("href"); return; } } $(this).parent("li").toggleClass("active").children("ul").collapse("toggle"); if ($toggle) { $(this).parent("li").siblings().removeClass("active").children("ul.in").collapse("hide"); } }); }, isIE: function() { //https://gist.github.com/padolsey/527683 var undef, v = 3, div = document.createElement("div"), all = div.getElementsByTagName("i"); while ( div.innerHTML = "<!--[if gt IE " + (++v) + "]><i></i><![endif]-->", all[0] ) { return v > 4 ? v : undef; } }, //Enable the link on the second click. doubleTapToGo: function(elem) { var $this = this.element; //if the class "doubleTapToGo" exists, remove it and return if (elem.hasClass("doubleTapToGo")) { elem.removeClass("doubleTapToGo"); return true; } //does not exists, add a new class and return false if (elem.parent().children("ul").length) { //first remove all other class $this.find(".doubleTapToGo").removeClass("doubleTapToGo"); //add the class on the current element elem.addClass("doubleTapToGo"); return false; } }, remove: function() { this.element.off("." + pluginName); this.element.removeData(pluginName); } }; $.fn[pluginName] = function(options) { this.each(function () { var el = $(this); if (el.data(pluginName)) { el.data(pluginName).remove(); } el.data(pluginName, new Plugin(this, options)); }); return this; }; })(jQuery, window, document);
<<metisMenu.css>>
/* * metismenu - v1.1.3 * Easy menu jQuery plugin for Twitter Bootstrap 3 * https://github.com/onokumus/metisMenu * * Made by Osman Nuri Okumus * Under MIT License */ .arrow { float: right; line-height: 1.42857; } .glyphicon.arrow:before { content: "\e079"; } .active > a > .glyphicon.arrow:before { content: "\e114"; } /* * Require Font-Awesome * http://fortawesome.github.io/Font-Awesome/ */ .fa.arrow:before { content: "\f104"; } .active > a > .fa.arrow:before { content: "\f107"; } .plus-times { float: right; } .fa.plus-times:before { content: "\f067"; } .active > a > .fa.plus-times { filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); -webkit-transform: rotate(45deg); -moz-transform: rotate(45deg); -ms-transform: rotate(45deg); -o-transform: rotate(45deg); transform: rotate(45deg); } .plus-minus { float: right; } .fa.plus-minus:before { content: "\f067"; } .active > a > .fa.plus-minus:before { content: "\f068"; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!