Bootstrap选项卡与Masonry插件的完美结合


Posted in Javascript onJuly 06, 2016

Bootstrap 是最流行的前端框架之一。在你的项目中使用Bootstrap,你就可以很快的实现响应式的网页。

如果你尝试将Masonry和Bootstrap提供的众多JavaScript组件之一的 选项卡组件 一起使用,你将会发现许多讨厌的行为。

我遇到过,而本文主要关注这个问题是什么和你要如何来解决这个问题。

Bootstrap的Tabs

Bootstrap的选项卡组件包括两个关键点:选项卡导航元素和一些内容面板。在页面加载时,第一个面板应用了 .active 类。使这个面板默认是可见的。这个类是通过使用JavaScript来切换面板的可见性,通过选项卡导航触发的事件:如果这个面板现在拥有 .active 类那它是可见的,否则这个面板就是隐藏的。

如果你有一些网页内容最好是在单独的块中而不是挤在一个地方,那这种选项卡组件可能派上用场。

为什么是Maronry?

在一些情况下,在每个面板内的内容是适合被显示在响应式的网格布局内的。例如,一系列的商品,服务和文件夹项目都是可以被显示在网格格式内的内容类型。

然而,如果网格的格子不是相同的高度,那像如你所看到的下面的情况将会发生。

Bootstrap选项卡与Masonry插件的完美结合 

两行之间被一些大的间距撑开,使布局看上去好难看。

这就是Masonry解决问题的时候了。加一些Masonry功能到这个混乱的布局中,然后你的布局会动态的适应屏幕的实际面积,消除所有损坏布局的空白间距。

Bootstrap选项卡与Masonry插件的完美结合 

设置DEMO页面

制作一个示例页面用来展示如何整合Bootstrap的标签页和Masonry并不像期望的那么简单。

本文的演示案例 是基于在Bootstrap网站上可用的起始模板 制作的

每个在选项卡面板中的网格项目都是用 Bootstrap的网格系统 和 缩略图组件 建立的。这里是一个代码片段来解释它的结构:

<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="http://lorempixel.com/200/200/abstract" alt="">
<div class="caption">
<h3>Thumbnail label</h3>
<p>...</p>
<p>
<a href="#" class="btn btn-primary" role="button">Button</a> 
<a href="#" class="btn btn-default" role="button">Button</a>
</p>
</div>
</div>
</div> 
<!-- Repeat two more times ... -->

上面的代码创建了一个在大型屏幕上为三列,在小型屏幕上为两列的网格。如果你需要复习一下Bootstrap的网格系统,Syed Fazle Rahman写的理解Bootstrap的网格系统是一篇很好的 文章 。

示例页面中的选项卡组件有如下的HTML结构:

<div role="tabpanel">
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active">
<a href="#panel-1" aria-controls="panel-1" role="tab" data-toggle="tab">Panel 1</a>
</li>
<li role="presentation">
<a href="#panel-2" aria-controls="panel-2" role="tab" data-toggle="tab">Panel 2</a>
</li>
<li role="presentation">
<a href="#panel-3" aria-controls="panel-3" role="tab" data-toggle="tab">Panel 3</a>
</li>
<li role="presentation">
<a href="#panel-4" aria-controls="panel-4" role="tab" data-toggle="tab">Panel 4</a>
</li>
</ul>
<!-- Tab panels -->
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="panel-1">
<div class="row masonry-container">
<div class="col-md-4 col-sm-6 item">
<!-- Thumbnail goes here -->
</div>
<div class="col-md-4 col-sm-6 item">
<!-- Thumbnail goes here -->
</div>
<div class="col-md-4 col-sm-6 item">
<!-- Thumbnail goes here -->
</div>
...
</div><!--End masonry-container -->
</div><!--End panel-1 -->
<div role="tabpanel" class="tab-pane" id="panel-2">
<!-- Same as what goes inside panel-1 -->
</div><!--End panel-2 -->
...
</div><!--End tab-content -->
</div><!--End tabpanel -->

这里有一些关于上面代码片段的注意事项:

HTML注释指出了选项卡的关键部件: Nav tabs 标志选项卡的导航部分, Nav panels 标志着内容面板。
选项卡的链接通过它们 href 属性的值连接到相应的 id 属性的值相同的内容面板。例如,有着 href="#panel-1" 的链接打开有着 id=panel-1 的内容面板。

在导航部分的每个锚标签都包含 data-toggle="tab" .这个标记使选项卡组件工作而无需写任何额外的JavaScript.
Masonry的目标元素需要有 .masonry-container 类,这个类适用于包含所有网格项目的包装器 div 元素,还需要应用于每单个网格项目的 .item 类。

要看到Masonry库的全部威力,一定要确保网格项目有不同的高度。例如,删除一个项目的图片,缩短另一个项目的段落,等等。

完整的代码,请在CodePen中查看示例的代码 。

添加Masonry库

你可以在 Masonry官网 上通点击”Download“ 按钮下载 masonry.pkgd.min.js 。

为了避免布局问题,库的作者推荐将Masonry与imagesLoaded 插件 一起使用。

Masonry不需要 jQuery 。但是因为Bootstrap的JavaScript组件已经在使用jQuery,以jQuery的方式初始化Masonry我将会使我自己的生活更加美好。

这是我们用jQuery和imagesLoaded初始化Masonry需要的代码段。

var $container = $('.masonry-container');
$container.imagesLoaded( function () {
$container.masonry({
columnWidth: '.item',
itemSelector: '.item'
}); 
});

上面的代码将包裹所有网格项目的 div 存储在一个叫 $container 的变量中。

接下来,Masonry在 $container 上用两个推荐选项进行初始化。 columnWidth 选项表明一个水平网格的一列的宽度。在这里是通过用单个网格项目的类名来设置单个网格项目的宽度的。 itemSelector 选项表明哪个子元素被用作项目元素。在这里,也设定为单个网格项目。

现在是时候来测试代码了。

哎呀!隐藏的面板怎么了?

在一个不使用Bootstrap选项卡的网页上,上面的代码就像施了魔法。然而,在这种情况下,你很快就会发现一种有趣的行为出现。

首先,它看起来不错,因为默认显示的选项卡面板内的网格是显示正确的:

Bootstrap选项卡与Masonry插件的完美结合 

但是,如果你点击选项卡导航链接显示隐藏的面板的内容,就会发生下面的情况:

Bootstrap选项卡与Masonry插件的完美结合 

查看源码,Masonry已经如预期那样触发了,但是每个项目的位置没有被正确的计算:网格项目都像一副纸牌一样堆在一起。

这还不是全部。调整浏览器窗口的大小会使这些网格项目正确定位自己。

让我们来解决这个布局的错误

因为这个出乎意料的布局错误在点击选项卡的导航链接之后变得更明显,那么让我们更密切的观察Bootstrap选项卡触发的事件。

事件列表 非常的短。如下。

show.bs.tab 触发标签页显示,但是是在新的标签页显示之前
shown.bs.tab 触发标签页显示,在标签页显示之后
hide.bs.tab 在新的标签页将显示的时候触发(因此前一个显示的标签页将被隐藏)
hidden.bs.tab 在一个新的标签页显示之后触发(因此前一个显示的标签页是隐藏的)

因为网格布局弄乱是在标签页已经被显示之后,所以我们去找 shown.bs.tab 事件。我们将这里的代码放置到我们原先代码的下面:

$('a[data-toggle=tab]').each(function () {
var $this = $(this);
$this.on('shown.bs.tab', function () {
$container.imagesLoaded( function () {
$container.masonry({
columnWidth: '.item',
itemSelector: '.item'
}); 
}); 
});
});

上面的代码中发生了什么:

jQuery .each() 函数循环遍历每个选项卡导航链接,监听shown.bs.tab事件。在这个事件触发时,对应的面板变成可见的,同时Masonry在所有的图片完成加载后重新初始化。

让我们来测试代码

如果你一直跟着文章操作,直接在您的浏览器中启动您的示例页面,或者试试下面的CodePen示例来看看结果。

你可能也想看一下 完整的示例页面 来测试响应式布局效果。

点击选项卡导航链接,注意这个时候网格项目如何在每个面板中适合均匀。改变浏览器的大小会导致网格项目正确的重新定位自己的位置,并有一个漂亮的动画效果。

就是这样,任务完成!

结论

在这篇文章中我已经展示了如何整合Bootstrap的标签页和Masonry JavaScript库。

这两个脚本都容易使用并且非常强大。然而,将它们两个放到一起你将会面临一些影响隐藏的选项卡的布局漏洞。如上面所示,诀窍就是在每个面板变成可见之后重新初始化Masonry库。

Javascript 相关文章推荐
JavaScript入门教程(8) Location地址对象
Jan 31 Javascript
推荐10个超棒的jQuery工具提示插件
Oct 11 Javascript
jquery mobile实现拨打电话功能的几种方法
Aug 05 Javascript
如何将网页表格内容导入excel
Feb 18 Javascript
jquery解析XML字符串和XML文件的方法说明
Feb 21 Javascript
js图片轮播手动切换效果
Nov 10 Javascript
学习javascript面向对象 理解javascript原型和原型链
Jan 04 Javascript
Node.js常用工具之util模块
Mar 09 Javascript
JS简单实现查看文档创建日期、修改日期和文档大小的方法示例
Apr 08 Javascript
JavaScript实现新年倒计时效果
Nov 17 Javascript
vue页面引入three.js实现3d动画场景操作
Aug 10 Javascript
vue router 动态路由清除方式
May 25 Vue.js
针对BootStrap中tabs控件的美化和完善(推荐)
Jul 06 #Javascript
jQuery插件dataTables添加序号列的方法
Jul 06 #Javascript
Spring MVC中Ajax实现二级联动的简单实例
Jul 06 #Javascript
js中window.open的参数及注意注意事项
Jul 06 #Javascript
快速解决js动态改变dom元素属性后页面及时渲染的问题
Jul 06 #Javascript
jQuery 3.0十大新特性
Jul 06 #Javascript
Javascript 基础---Ajax入门必看
Jul 06 #Javascript
You might like
PHP中file_exists使用中遇到的问题小结
2016/04/05 PHP
php和html的区别点详细总结
2019/09/24 PHP
优化JavaScript脚本的性能的几个注意事项
2006/12/22 Javascript
javascript 字符串连接的性能问题(多浏览器)
2008/11/18 Javascript
JQuery 写的个性导航菜单
2009/12/24 Javascript
让人印象深刻的10个jQuery手风琴效果应用
2012/05/08 Javascript
js用Date对象处理时间实现思路及代码
2013/01/31 Javascript
java与javascript之间json格式数据互转介绍
2013/10/29 Javascript
浅析JavaScript中的CSS属性及命名规范
2013/11/28 Javascript
JavaScript中的闭包(Closure)详细介绍
2014/12/30 Javascript
浅谈$(document)和$(window)的区别
2015/07/15 Javascript
JS 动态判断PC和手机浏览器实现代码
2016/09/21 Javascript
JS调用Android、Ios原生控件
2017/01/06 Javascript
jQuery实现淡入淡出的模态框
2017/02/09 Javascript
详谈js遍历集合(Array,Map,Set)
2017/04/06 Javascript
详解webpack自定义loader初探
2018/08/29 Javascript
微信小程序实现分享商品海报功能
2019/09/30 Javascript
Servlet返回的数据js解析2种方法
2019/12/12 Javascript
JS实现普通轮播图特效
2020/01/01 Javascript
[01:14:35]DOTA2上海特级锦标赛B组资格赛#1 Alliance VS Fnatic第一局
2016/02/26 DOTA
Python入门_浅谈for循环、while循环
2017/05/16 Python
virtualenv 指定 python 解释器的版本方法
2018/10/25 Python
DataFrame:通过SparkSql将scala类转为DataFrame的方法
2019/01/29 Python
详解Python 切片语法
2019/06/10 Python
用Python实现校园通知更新提醒功能
2019/11/23 Python
彻底搞懂python 迭代器和生成器
2020/09/07 Python
一款恶搞头像特效的制作过程 利用css3和jquery
2014/11/21 HTML / CSS
HTML5探秘:用requestAnimationFrame优化Web动画
2018/06/03 HTML / CSS
欧洲著名的珠宝和手表网上商城:uhrcenter
2017/04/10 全球购物
四风问题自查报告剖析材料
2014/02/08 职场文书
机关单位人员学雷锋心得体会
2014/03/10 职场文书
商超业务员岗位职责
2014/03/12 职场文书
2015年信访维稳工作总结
2015/04/07 职场文书
涨价通知
2015/04/23 职场文书
浅谈Java实现分布式事务的三种方案
2021/06/11 Java/Android
Python Pygame实战在打砖块游戏的实现
2022/03/17 Python