JS组件系列——基于Bootstrap Ace模板的菜单Tab页效果优化
Posted 懒得安分
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS组件系列——基于Bootstrap Ace模板的菜单Tab页效果优化相关的知识,希望对你有一定的参考价值。
前言:之前发表过一篇 JS组件系列——基于Bootstrap Ace模板的菜单和Tab页效果分享(你值得拥有) ,收到很多园友的反馈,当然也包括很多诟病,因为上篇只是将功能实现了,很多细节都没有处理,这篇博主将带领大家一起来优化这里的效果,使之成为一个可以在项目里面使用的成品。
说点题外话,本来,在互联网模式下,Tab页+iframe的组合是不能被大多数平台接受的,从这些年推出的一些好的产品可以看出,几乎大家都不这么玩,即使是一些后台的管理模板,比如常见的AdminLTE、Ace、I
系列文章
解决iframe高度自适应问题
增加上边框
美化删除图标
标签页上面显示菜单图标
标签增加边框
方角边框
标签颜色搭配
标签过多时左右移动
菜单选中效果
菜单独立滚动条
var changeFrameHeight = function (that) { $(that).height(document.documentElement.clientHeight - 115); $(that).parent(".tab-pane").height(document.documentElement.clientHeight - 130); }
然后创建iframe的时候调用这个方法
content = \'<div role="tabpanel" class="tab-pane" id="\' + id + \'"><iframe id="iframe_\'+id+\'" src="\' + options.url + \'" width="100%" height="100%" onload="changeFrameHeight(this)" frameborder="no" border="0" marginwidth="0" marginheight="0" scrolling="yes" allowtransparency="yes"></iframe></div>\';
为了在浏览器的宽高变化时页面的宽高也跟着变化,还需要注册页面的onresize事件
window.onresize = function () { var target = $(".tab-content .active iframe"); changeFrameHeight(target); }
这三个地方都在bootstrap-tab.js里面更改即可。
改完之后来看看测试效果:
新建文件,然后在index.html页面引用该样式文件
<link href="Content/bootstrap/css/bootstrap-tab.css" rel="stylesheet"/>
我们增加两个样式
.nav-tabs li a{ line-height:2 } .nav-tabs .active a{ border-top: solid 2px #3498db !important; }
查看效果
是不是看上去赶紧好好看一些~~
3、美化删除图标
上图中标签页加上上边框之后看上去要好看一些了,可是还不够美观,看来看去总觉得哪个关闭的小图标怪怪的,我们来美化一下。比如我们在boostrap-tab.js里面将关闭按钮换成带圆形边框的
将图标i标签的的class由原来的 glyphicon glyphicon-remove 换成 glyphicon glyphicon-remove-sign 即可,我们来看看效果:
为了更加符合使用习惯,我们增加一个鼠标移动到图标上面显示红色的效果,我们在boostrap-tab.css里面增加如下样式:
.nav-tabs li a .glyphicon-remove-sign:hover{ color:red; cursor: pointer; }
效果如下
4、标签页带图标
标签页里面仅仅显示文字和关闭的图标给人感觉太空洞,我们增加页面的图标。首先首页的标签页我们增加一个home图标,在index.html增加如下i标签:
然后其他每一个动态打开的tab页前面的图标就是对应的点击左边菜单对应的图标。首先我们在初始化菜单的那个做如下更改,在sidebar-menu.js文件改成这样
(function ($) { $.fn.sidebarMenu = function (options) { options = $.extend({}, $.fn.sidebarMenu.defaults, options || {}); var target = $(this); target.addClass(\'nav\'); target.addClass(\'nav-list\'); if (options.data) { init(target, options.data); } else { if (!options.url) return; $.getJSON(options.url, options.param, function (data) { init(target, data); }); } var url = window.location.pathname; //menu = target.find("[href=\'" + url + "\']"); //menu.parent().addClass(\'active\'); //menu.parent().parentsUntil(\'.nav-list\', \'li\').addClass(\'active\').addClass(\'open\'); function init(target, data) { $.each(data, function (i, item) { var li = $(\'<li></li>\'); var a = $(\'<a></a>\'); var icon = $(\'<i></i>\'); //icon.addClass(\'glyphicon\'); icon.addClass(item.icon); var text = $(\'<span></span>\'); text.addClass(\'menu-text\').text(item.text); a.append(icon); a.append(text); if (item.menus&&item.menus.length>0) { a.attr(\'href\', \'#\'); a.addClass(\'dropdown-toggle\'); var arrow = $(\'<b></b>\'); arrow.addClass(\'arrow\').addClass(\'icon-angle-down\'); a.append(arrow); li.append(a); var menus = $(\'<ul></ul>\'); menus.addClass(\'submenu\'); init(menus, item.menus); li.append(menus); } else { var href = \'javascript:addTabs({id:\\\'\' + item.id + \'\\\',title: \\\'\' + item.text + \'\\\',close: true,url: \\\'\' + item.url + \'\\\',icon:\\\'\'+ item.icon +\'\\\'});\'; a.attr(\'href\', href); //if (item.istab) // a.attr(\'href\', href); //else { // a.attr(\'href\', item.url); // a.attr(\'title\', item.text); // a.attr(\'target\', \'_blank\') //} li.append(a); } target.append(li); }); } } $.fn.sidebarMenu.defaults = { url: null, param: null, data: null }; })(jQuery);
其中有一句
var href = \'javascript:addTabs({id:\\\'\' + item.id + \'\\\',title: \\\'\' + item.text + \'\\\',close: true,url: \\\'\' + item.url + \'\\\',icon:\\\'\'+ item.icon +\'\\\'});\';
这里将当前菜单的图标传到addTabs()方法里面,然后在addTabs()方法里面接收这个参数。
var addTabs = function (options) { //可以在此处验证session //var rand = Math.random().toString(); //var id = rand.substring(rand.indexOf(\'.\') + 1); debugger; var url = window.location.protocol + \'//\' + window.location.host; options.url = url + options.url; id = "tab_" + options.id; var active_flag = false; if($("#" + id)){ active_flag = $("#" + id).hasClass(\'active\'); } $(".active").removeClass("active"); //如果TAB不存在,创建一个新的TAB if (!$("#" + id)[0]) { //固定TAB中IFRAME高度 mainHeight = $(document.body).height(); //创建新TAB的title title = \'<li role="presentation" id="tab_\' + id + \'"><a href="#\' + id + \'" aria-controls="\' + id + \'" role="tab" data-toggle="tab"><i class="\'+options.icon+\'"></i>\' + options.title; //是否允许关闭 if (options.close) { title += \' <i class="glyphicon glyphicon-remove-sign" tabclose="\' + id + \'"></i>\'; } title += \'</a></li>\'; //是否指定TAB内容 if (options.content) { content = \'<div role="tabpanel" class="tab-pane" id="\' + id + \'">\' + options.content + \'</div>\'; } else {//没有内容,使用IFRAME打开链接 content = \'<div role="tabpanel" class="tab-pane" id="\' + id + \'"><iframe id="iframe_\'+id+\'" src="\' + options.url + \'" width="100%" height="100%" onload="changeFrameHeight(this)" frameborder="no" border="0" marginwidth="0" marginheight="0" scrolling="yes" allowtransparency="yes"></iframe></div>\'; } //加入TABS $(".nav-tabs").append(title); $(".tab-content").append(content); }else{ if(active_flag){ $("#iframe_" + id).attr(\'src\', $("#iframe_" + id).attr(\'src\')); } } //激活TAB $("#tab_" + id).addClass(\'active\'); $("#" + id).addClass("active"); }; var changeFrameHeight = function (that) { $(that).height(document.documentElement.clientHeight - 115); $(that).parent(".tab-pane").height(document.documentElement.clientHeight - 130); } var closeTab = function (id) { //如果关闭的是当前激活的TAB,激活他的前一个TAB if ($("li.active").attr(\'id\') == "tab_" + id) { $("#tab_" + id).prev().addClass(\'active\'); $("#" + id).prev().addClass(\'active\'); } //关闭TAB $("#tab_" + id).remove(); $("#" + id).remove(); }; $(function () { $("[addtabs]").click(function () { addTabs({ id: $(this).attr("id"), title: $(this).attr(\'title\'), close: true }); }); $(".nav-tabs").on("click", "[tabclose]", function (e) { id = $(this).attr("tabclose"); closeTab(id); }); window.onresize = function () { var target = $(".tab-content .active iframe"); changeFrameHeight(target); } });
其中有一句
title = \'<li role="presentation" id="tab_\' + id + \'"><a href="#\' + id + \'" aria-controls="\' + id + \'" role="tab" data-toggle="tab"><i class="\'+options.icon+\'"></i>\' + options.title;
然后写一个样式调整标签页图标和标题的距离,我们在bootstrap-tab.css里面增加如下样式:
.nav-tabs li a i:first-child{ margin-right: 3px; }
最终得到效果如下:
当然,有可能你觉得加上这个之后tab页显得很拥挤,你也可以不加,根据自己的喜好来进行美化
5、标签页增加边框
经过上面三步骤的美化,我们的标签页已经好看了许多。如果你对界面要求不高,其实也够了,但是博主觉得还可以继续美化呢~
比如我们给标签也增加一个边框,使每一个标签页看上去更加像一个独立的整体。我们调整.nav-tabs li a这个样式为
.nav-tabs li a{ line-height:2; border:1px #ddd solid; margin-right: -1px; color: #999; }
然后增加
.nav-tabs{ background: #fafafa; }
这样看到的效果:
当然,有人喜欢将边框的圆角去掉,你也可以在.nav-tabs li a里面增加 border-radius:0; 得到的效果
博主觉得使用圆角也不错啊,反正这个取决于个人喜好!
6、标签页颜色搭配
以上效果基本够用,在项目里面使用起来没有太大的问题,但博主还想将其优化下。比如我们做如下样式调整:
.nav-tabs{ background: #fafafa; border-bottom: 3px #3498db solid; } .nav-tabs li a{ line-height:2; border:1px #ddd solid; margin-right: -1px; color: #999; border-radius: 0; } .nav-tabs li a .glyphicon-remove-sign:hover{ color:red; cursor: pointer; } .nav-tabs li a i:first-child{ margin-right: 3px; } .nav-tabs .active a{ border-top: solid 2px #3498db !important; background: #3498db !important; color:#fff !important; }
可能这里的颜色搭配并不协调,但至少看上去更加perfect一点吧。
7、标签页宽度超限处理
到上面为止Tab页的样式已经可以了,可是还有一个最大的问题没有解决,就是当所有tab页的宽度的和超过浏览器的宽度限制时,就会出现tab的换行,看上去非常“恶心”。不信你多打开一些tab页试试。这里博主花了两天时间写了一套可行的样式方案,来一睹风采吧:
实现思路其实不难,主要就是界面样式的调整确实非常话时间。下面来看一看实现步骤
首先界面上面在标签页的两边增加向左移、向右移的图标
<ul class="nav-my-tab"> <li class="leftbackward"><a href="#" > <i class="icon-backward"></i></a> </li> <li class="middletab"> <ul class="nav nav-tabs" role="tablist"> <li class="active"><a href="#Index" role="tab" data-toggle="tab"> <i class="icon-home"></i>系统首页</a> </li> </ul> </li> <li class="rightforward"><a href="#"> <i class="icon-forward"></i></a> </li> </ul>
然后就是这两个图标以及中间tab页的样式
.nav-my-tab{ padding-left: 0px; margin-bottom: 0px; } .nav-my-tab .middletab{ height: 36px; overflow: hidden; border-bottom: 3px #3498db solid; position: relative; background: #fafafa; } .nav-my-tab li{ list-style-type: none; } .nav-my-tab li a{ padding:5px 10px; } .nav-my-tab .leftbackward{ float: left; background: #fff; padding-top: 7px; border-top: 1px #ddd solid; height:36px; border-bottom: 3px #3498db solid; } .nav-my-tab .leftbackward a{ border-left-width: 0px; color: #999; padding-top: 9px; padding-bottom: 8px; margin-right: -1px; } .nav-my-tab .leftbackward a:hover,.nav-my-tab .leftbackward a:focus{ text-decoration: none; background: #ddd; } .nav-my-tab .rightforward{ float:right; position: relative; line-height: 2.6; background: #fff; border-top: 1px #ddd solid; border-bottom: 3px #3498db solid; } .nav-my-tab .rightforward a{ width: 35.5px; line-height: 2; color: #999; height: 35px; padding: 8px 10px; padding-left: 13px; border-left: 1px #ddd solid; } .nav-my-tab .rightforward a:hover,.nav-my-tab .rightforward a:focus{ text-decoration: none; background: #ddd; }
最后就是左移、右移的按钮事件
$(function () { $("[addtabs]").click(function () { addTabs({ id: $(this).attr("id"), title: $(this).attr(\'title\'), close: true }); }); $(".nav-tabs").on("click", "[tabclose]", function (e) { id = $(this).attr("tabclose"); closeTab(id); }); $(\'.nav-my-tab .middletab\').width($(\'.nav-my-tab .middletab\').width()-37); //固定左边菜单的高度 $(\'#sidebar\').height($(window).height() - 80); window.onresize = function () { var target = $(".tab-content .active iframe"); changeFrameHeight(target); } //tab页向左向右移动 $(\'.nav-my-tab .leftbackward\').click(function(){ var strLeft=$(\'.nav-my-tab .middletab .nav-tabs\').css(\'left\'); var iLeft = parseInt(strLeft.replace(\'px\', \'\')); if(iLeft>=0){ return; } else{ debugger; var totalWidth=0; var lis = $(".nav-tabs li"); for(var i=0;i<lis.length;i++){ var item = lis[i]; totalWidth-= $(item).width(); if(iLeft>totalWidth){ iLeft+=$(item).width(); break; } }; if(iLeft>0){ iLeft=0; } $(".nav-my-tab .middletab .nav-tabs").animate({left:iLeft + \'px\'}); } }); $(\'.nav-my-tab .rightforward\').click(function(){ var strLeft=$(\'.nav-my-tab .middletab .nav-tabs\').css(\'left\'); var iLeft = parseInt(strLeft.replace(\'px\', \'\')); var totalWidth=0; $.each($(".nav-tabs li"),function(key, item){ totalWidth+= $(item).width(); }); var tabsWidth = $(".nav-my-tab .middletab").width(); if(totalWidth>tabsWidth){ debugger; if(totalWidth-tabsWidth<=Math.abs(iLeft)){ return; } var lis = $(".nav-tabs li"); totalWidth=0; for(var i=0;i<lis.length;i++){ var item = lis[i]; totalWidth-= $(item).width(); if(iLeft>totalWidth){ iLeft-=$(item).width(); break; } }; $(".nav-my-tab .middletab .nav-tabs").animate({left:iLeft + \'px\'}); } }); });
主要原理就是通过计算所有tab页的宽度的和已经ul当前的左移量来判断是否需要移动,以及每次移动多少。这里的移动是通过css样式的left属性去控制的。如果你理解了这个原理,其实实现起来并不算太复杂,关键的问题还是页面的样式和js的配置使用。
8、左边菜单的选中效果和固定高度效果
这部分其实不属于Tab页的优化范畴,但既然要把这个做好,顺带也把这个优化了下。
首先在sidebar-menu.js里面增加如下id
然后在addTabs()方法的最下面加这两句即可
//激活左边菜单 $(\'#menu li\').removeClass(\'active\'); $(\'#li_\'+options.id).addClass(\'active\');
得到效果
还有一个就是左边菜单的滚动条,当左边菜单的数量多了以后,每次展开都会导致整个页面出现滚动条,界面非常不友好,博主打算给左边菜单部分单独加上滚动条,用来控制菜单的滚动。
增加如下样式
#sidebar{ overflow-x: hidden; overflow-y: auto; }
这里的sidebar是左边菜单的div容器。
然后在页面初始化完成的时候给这个div固定一个动态高度。
$(function () { //固定左边菜单的高度 $(\'#sidebar\').height($(window).height() - 80); });
效果如下
源码下载地址:https://download.csdn.net/download/landeanfen/12323940
本文原创出处:http://www.cnblogs.com/landeanfen/
欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利
PS:感谢给位园友的支持和厚爱,源码已经贴出来了,有需要的可以自行下载。欢迎关注!
以上是关于JS组件系列——基于Bootstrap Ace模板的菜单Tab页效果优化的主要内容,如果未能解决你的问题,请参考以下文章
Bootstrap ACE后台管理界面模板-jquery已整理
hangfire+bootstrap ace 模板实现后台任务管理平台
JS组件系列——两种bootstrap multiselect组件大比拼