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 相关文章推荐
网页整体变灰白色(兼容各浏览器)实例
Apr 21 Javascript
JS中使用Array函数shift和pop创建可忽略参数的例子
May 28 Javascript
jquery访问ashx文件示例代码
Aug 11 Javascript
jQuery实现渐变下拉菜单的简单方法
Mar 11 Javascript
jQuery的promise与deferred对象在异步回调中的作用
May 03 Javascript
浅谈js图片前端预览之filereader和window.URL.createObjectURL
Jun 30 Javascript
jQuery mobile在页面加载时添加加载中效果 document.ready 和window.onload执行顺序比较
Jul 14 Javascript
JavaScript中利用构造器函数模拟类的方法
Feb 16 Javascript
JS简单获取当前日期和农历日期的方法
Apr 17 Javascript
React学习之事件绑定的几种方法对比
Sep 24 Javascript
解决Vue.js 2.0 有时双向绑定img src属性失败的问题
Mar 14 Javascript
javascript 设计模式之享元模式原理与应用详解
Apr 08 Javascript
针对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
手冲咖啡应该是现代精品咖啡店的必备选项吗?
2021/03/03 冲泡冲煮
php注销代码(session注销)
2012/05/31 PHP
php使用ICQ网关发送手机短信
2013/10/30 PHP
php生成二维码时出现中文乱码的解决方法
2014/12/18 PHP
php打印输出棋盘的实现方法
2014/12/23 PHP
php连接oracle数据库的方法(测试成功)
2016/05/26 PHP
PHP判断JSON对象是否存在的方法(推荐)
2016/07/06 PHP
PHP实现在数据库百万条数据中随机获取20条记录的方法
2017/04/19 PHP
基于逻辑运算的简单权限系统(实现) JS 版
2007/03/24 Javascript
JavaScript splice()方法详解
2020/09/22 Javascript
jquery mobile的触控点击事件会多次触发问题的解决方法
2014/05/08 Javascript
js 模式窗口(模式对话框和非模式对话框)的使用介绍
2014/07/17 Javascript
JS基于面向对象实现的拖拽功能示例
2016/12/20 Javascript
ES6学习教程之对象的扩展详解
2017/05/02 Javascript
js轮播图无缝滚动效果
2017/06/17 Javascript
vue中Npm run build 根据环境传递参数方法来打包不同域名
2018/03/29 Javascript
vue.js实现的经典计算器/科学计算器功能示例
2018/07/11 Javascript
JavaScript箭头函数中的this详解
2019/06/19 Javascript
javascript实现计算器功能
2020/03/30 Javascript
如何HttpServletRequest文件对象并储存
2020/08/14 Javascript
vue项目在线上服务器访问失败原因分析
2020/08/14 Javascript
vue 通过 Prop 向子组件传递数据的实现方法
2020/10/30 Javascript
python实现的一个p2p文件传输实例
2014/06/04 Python
Python中的异常处理简明介绍
2015/04/13 Python
Python实现将一个大文件按段落分隔为多个小文件的简单操作方法
2017/04/17 Python
python爬虫获取百度首页内容教学
2018/12/23 Python
python字典改变value值方法总结
2019/06/21 Python
浅谈django channels 路由误导
2020/05/28 Python
APM Monaco中国官网:来自摩纳哥珠宝品牌
2017/12/27 全球购物
Mansur Gavriel官网:纽约市的一个设计品牌
2019/05/02 全球购物
路由表示做什么用的?在linux环境中怎么来配置一条默认路由?
2013/06/07 面试题
青年文明号申报材料
2014/12/23 职场文书
2015年班长个人工作总结
2015/04/03 职场文书
2015年信息技术教研组工作总结
2015/07/22 职场文书
2016年小学生迎国庆广播稿
2015/12/18 职场文书
德劲DE1107指针试高灵敏度全波段收音机机评
2022/04/05 无线电