網頁上的空間是寸土寸金,雖然顯示器的解析度越來越大,可是直到今天,網頁設計中仍然是以至少1024x768 像素的支援為主,也就是說,每一屏頁面只有區區 955x600像素 的安全尺寸可以用而已。於是,為了在有限的空間裡容納更多的內容,滑動門式的標籤切換(Tabs)方式越來越受歡迎。通過滑動門技術,可以在同一塊頁面地區內放置數倍的內容。根據使用者的選擇來決定顯示哪一部分。最近我在實際應用中,逐步完善出一種基於 jQuery,但是比 jQuery UI Tabs 外掛程式更小巧也更通用的簡單 Tabs 實現。
最早的滑動門的技術,一般都是結合 onclick 或者 onmouseover 事件傳遞一個參數給 JS 函數,根據傳遞的參數來決定顯示哪一個標籤。比如:
function showTabs(n) { var tabsNumber = 3; for (i = 0; i < tabsNumber; i++) { if (i == n) { document.getElementById("tabPanel-" + i).style.display = "block"; } else { document.getElementById("tabPanel-" + i).style.display = "none"; } }}
加入有這樣的一個函數,就可以在tab的標題按鈕中設定 onclick = “showTabs(1)”來設定第二塊內容顯示,而其它塊隱藏。
這種方式最大的缺點是:
- HTML代碼和JS代碼混合;
- 可擴充性差;
儘管可以通過window.onload綁定事件等方式來是實現JS代碼從HTML中分離,也可以把函數改得更複雜以實現通用性。但是總的來說,還是很難做到一處定義到處引用。
後來隨著各種JS類庫的出現,更強大的Tabs出現了,最出名的就是jQuery UI中的tabs外掛程式。一旦載入了jQuery架構和jQuery UI外掛程式,那麼要在頁面中實現Tabs,就變得簡單了許多。首先我們的頁面中的Tabs代碼這樣寫:
<div class="tabs"> <ul> <li><a href="#panel-1">標籤一</a></li> <li><a href="#panel-2">標籤二</a></li> </ul> <div id="panel-1">地區一</div> <div id="panel-2">地區二</div></div>
注意:這裡的代碼非常乾淨,不含任何的JS代碼或者與文檔結構無關的定義。然後,在head地區,或者在頁面任何地方增加一段js代碼:
$(function() { $(".tabs").tabs();});
就實現了Tabs功能,這行JS代碼執行後,上面的HTML代碼就會變成:
<div class="tabs"> <ul class="ui-tabs-nav" jquery1239647486215="2"> <li class="ui-tabs-selected"><a href="#panel-1" jquery1239647486215="8">標籤一</a></li> <li><a href="#panel-2" jquery1239647486215="9">標籤二</a></li> ></ul> <div id="panel-1" class="ui-tabs-panel" jquery1239647486215="4"> 地區一 </div> <div id="panel-2" class="ui-tabs-panel ui-tabs-hide" jquery1239647486215="5"> 地區二 </div></div>
結合我們自己編寫的css,或者jQuery UI 內建的CSS,就可以實現滑動門效果。並且,由於jQuery的強大,我們可以在頁面中放置多組滑動門,然後一次性設定。
要說明的是,這個地方由於只啟用了jQuery UI 中的 Tabs 外掛程式,因此產生的程式碼還是比較乾淨的,只增加了 ui-tabs-xxxx 這幾個相關的css類。如果你同時包含了jQuery UI的其它外掛程式,那麼即使不啟用,也會添加一堆的css定義。而且,jQuery UI Tabs 還提供了非常強大的控制功能,你可以動態地添加 tab,可以隨意更改啟用事件,可以定義轉場效果,還可以設定預設啟用狀態和禁用等。
但是我在實際應用中遇到了一些問題,除了 jQuery UI 內建的js指令碼很大,css不符合實際應用需求外,還有一個最大的問題,你可能已經注意到了,在作為導航的標籤定義中,每個標籤對應哪一個地區是用連結目標來定義的。比如 <a href="#panel-1">標籤一</a>和<div id="panel-1">地區一</div>對應,如果你的標籤和地區沒有對應起來,綁定tabs()就不起作用了。
而且,這種方式來帶來另一個麻煩,就是當我們需要給標籤加上連結的時候,沒辦法加。即使你將標籤的啟用事件設定為onmouseover而不是onclick,連結也不能實現,因為連結用於指定目標了。這種需求在我們的實際應用中並不是不存在的。比如:
這兩個圖片中的tabs標籤,都要添加到對應的新聞類別或者論壇板塊的連結。這時候 jQuery UI的預設綁定就帶來了麻煩。
其實分析一下,我們在實現滑動門的時候,用以下HTML結構就可以滿足需要:
<div class="tabs"> <ul> <li>標籤一</li> <li>標籤二</li> </ul> <div>地區一</div> <div>地區二</div></div>
藉助 jQuery 庫,我們可以通過 $(".tabs")找到要實現的標籤,然後 .find("li") 來找到要添加事件的元素,綁定事件的時候,我們可以通過該元素在$(".tabs li")集合中的索引值來明確是哪一個標籤被啟用,然後對應索引值的panel顯示。代碼類似這樣:
<script type="text/javascript"> $(function() { $(".tabs").find("li").onmouseover(function(e) { if (e.target == this) { var tabs = $(this).parent().children("li"); var panels = $(this).parent().parent().children("div"); var index = $.inArray(this, tabs); if (panels.eq(index)[0]) { tabs.removeClass("ui-tabs-selected") .eq(index).addClass("ui-tabs-selected"); panels.addClass("ui-tabs-hide") .eq(index).removeClass("ui-tabs-hide"); } } }); });</script>
這段代碼只使用了兩個css類來處理,並且,自動判斷tabs和panels的對應狀態,假如你有4個tab,但是只有前三個啟用了,那麼你只需要寫三個panel就可以,第四個panel不存在,則第四個tab自動不生效。
在實際使用中,會遇到一個問題,一般我們會給tab中的文字加連結,那麼當滑鼠滑過這個tab的時候,如果指到了文字,那麼激發事件的對象有可能是a元素而不是li元素,則事件就不能正確激發。所以我們改進代碼如下:
<script type="text/javascript"> $(function() { $(".ui-tabs-nav > li > a")onmouseover(function(e) { if (e.target == this) { var tabs = $(this).parent().parent().children("li"); var panels = $(this).parent().parent().parent().children(".ui-tabs-panel"); var index = $.inArray(this, tabs); if (panels.eq(index)[0]) { tabs.removeClass("ui-tabs-selected") .eq(index).addClass("ui-tabs-selected"); panels.addClass("ui-tabs-hide") .eq(index).removeClass("ui-tabs-hide"); } } }); });</script>
與此對應的HTML結構是:
<div> <ul class="ui-tabs-nav"> <li class="ui-tabs-selected"><a href="/bbs">論壇新帖</a></li> <li><a href="/blog">最新博文</a></li> </ul> <div class="ui-tabs-panel"> <!--這裡調用最新論壇文章--> </div> <div class="ui-tabs-panel ui-tabs-hide"> <!--這裡調用最新部落格文章--> </div></div>
同時,我們有以下的css類定義:
.ui-tabs-nav{ /*導航容器定義*/}.ui-tabs-nav li{ /*預設標籤樣式*/}.ui-tabs-nav li.ui-tabs-selected{ /*啟用的標籤樣式*/}.ui-tabs-panel{ /*預設的顯示地區樣式*/}.ui-tabs-hide{ display: none;}
這樣,就可以根據你的需要,結合自己的css,定製不同樣式的滑動門了。把相應的js代碼放到頁面中,那麼在頁面裡任何地方只要你按照HTML結構編寫了一段html,這段html就會自動變成滑動門。而不用在每個頁面裡單獨指定特定的selector來應用滑動門的tabs()方法。並且,根據需要給你的滑動門標籤添加需要的連結,或者不要連結(href="#" 或者 href="javascript:void(0)")。
這段滑動門代碼只要具有jQuery core 就可以正常運行,不需要載入jQuery UI。非常簡單,而且很通用,樣式上喜歡怎麼擴充都可以。
具體效果可以參見 http:/www.taihainet.com , 在 台海網 首頁中,我一共應用了四個樣式共九組滑動門,代碼就只是上面給出的那一段。四個樣式列舉如下:
滑動門一:多個搜尋表單,暫時只實現兩個,後面三個由於沒有對應的ui-tabs-panel,自動禁用,但是連結可以點擊。
滑動門二:多塊商務資訊地區,其中第三個由於沒有對應的ui-tabs-panel,自動禁用。
滑動門三:新聞欄目切換,標籤中的文字連結到對應的新聞欄目。
滑動門四:論壇分板塊文章調用。標籤中的文字連結到對應的論壇板塊。