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庫。