在Masonry网站,我们看到对Masonry描述:
...一个JavaScript网格布局库。其工作原理是基于可利用的垂直空间将元素放置在合适的位置,有点像一个泥瓦匠用合适的石头来堆砌墙。
Bootstrap是最流行的前端框架之一。在你的项目中使用Bootstrap,你就可以很快的实现响应式的网页。
如果你尝试将Masonry和Bootstrap提供的众多JavaScript组件之一的选项卡组件一起使用,你将会发现许多讨厌的行为。
我遇到过,而本文主要关注这个问题是什么和你要如何来解决这个问题。
Bootstrap的Tabs
Bootstrap的选项卡组件包括两个关键点:选项卡导航元素和一些内容面板。在页面加载时,第一个面板应用了.active
类。使这个面板默认是可见的。这个类是通过使用JavaScript来切换面板的可见性,通过选项卡导航触发的事件:如果这个面板现在拥有.active
类那它是可见的,否则这个面板就是隐藏的。
如果你有一些网页内容最好是在单独的块中而不是挤在一个地方,那这种选项卡组件可能派上用场。
为什么是Maronry?
在一些情况下,在每个面板内的内容是适合被显示在响应式的网格布局内的。例如,一系列的商品,服务和文件夹项目都是可以被显示在网格格式内的内容类型。
然而,如果网格的格子不是相同的高度,那像如你所看到的下面的情况将会发生。
两行之间被一些大的间距撑开,使布局看上去好难看。
这就是Masonry解决问题的时候了。加一些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选项卡的网页上,上面的代码就像施了魔法。然而,在这种情况下,你很快就会发现一种有趣的行为出现。
首先,它看起来不错,因为默认显示的选项卡面板内的网格是显示正确的:
但是,如果你点击选项卡导航链接显示隐藏的面板的内容,就会发生下面的情况:
查看源码,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库。
在你的工具箱中有这个解决方法,实现好的平铺的布局将会是一件轻而易举的事。
希望您喜欢读这篇文章。我很想在下面的讨论中听听您的想法。
本文根据@Maria Antonietta Perna的《Getting Bootstrap Tabs to Play Nice with Masonry》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://www.sitepoint.com/bootstrap-tabs-play-nice-with-masonry/。
如需转载,烦请注明出处:http://www.w3cplus.com/framework/bootstrap-tabs-play-nice-with-masonry.html