一、需求
最近一個項目中需要用到一個類似手風琴的效果,我立刻想到網上各種Accordion組件來實現。效果大致如下圖:
但看過了知名的幾款組件(包括Accordionza)均不能滿足這個需求。主要問題為:
- 只能在水平方向展示,不能用在垂直方向
- 只支持點擊切換,不支持鼠標滑過切換
- title欄只能在一個滑動項的頂部,不能自定義到底部
于是準備自己寫一個。
二、思路
假設有4張圖片,每張圖片的底部為標題并且疊加在圖片上面。當鼠標滑過每張的標題時,顯示該圖片的全部。
要實現鼠標滑過的垂直手風琴效果,我的思路大致如下:
- 容器為固定尺寸,切不允許溢出
- 子項目,即各張圖片均為絕對定位
- 初始化時,只把第一張圖片全部露出,其他圖片通過設置其top值和z-index值,均被上一張蓋住除標題以外的部分
- 當鼠標滑過某一張圖片的標題時,計算出要移走哪些圖片
- 改變需要移走的圖片的top值
下面再來仔細分析下一個實例中可能出現的情況。
當第1張顯示時:
- 如果鼠標指向第2張標題,則移走前1張;
- 如果鼠標指向第3張標題,則移走前2張;
- 如果鼠標指向第4張標題,則移走前3張;
反過來,當第4張顯示時: - 如果鼠標指向第3張標題,則移走第3張;
- 如果鼠標指向第2張標題,則移走第2、3張;
- 如果鼠標指向第1張標題,則移走第1、2、3張;
當顯示第2或第3張時,與上面兩個邊界情況類似。
規律就是: - 如果指向的圖片次序大于當前顯示圖片的次序,則上移當前以及它前面的圖片;如果指向的圖片的次序小于當前顯示圖片的次序,則下移它后面的圖片。
- 第4張,也就是最下面那張其實是不會動的。
三、代碼
HTML結構
<ul class="accd">
<li>
<img src="photo/c_04.jpg" />
<div>
<p class="t_04 s_02">Lorem</p>
<p class="d_02 s_02">consectetuer adipiscing elit</p>
<span>1</span>
</div>
</li>
<li>
<img src="photo/c_04.jpg" />
<div>
<p class="t_04 s_02">Claritas</p>
<p class="d_02 s_02">congue nihil imperdiet doming id</p>
<span>2</span>
</div>
</li>
<li>
<img src="photo/c_04.jpg" />
<div>
<p class="t_04 s_02">Eodem</p>
<p class="d_02 s_02">qui nunc nobis videntur parum </p>
<span>3</span>
</div>
</li>
<li>
<img src="photo/c_04.jpg" />
<div>
<p class="t_04 s_02">Typi</p>
<p class="d_02 s_02">placerat facer possim assum</p>
<span>4</span>
</div>
</li>
</ul>CSS
.accd{
height:655px;
overflow:hidden;
position:relative;
width:250px;
}
.accd li{
position:absolute;
overflow:hidden;
height:464px;
width:250px;
z-index:0;
}
.accd li div{
position:absolute;
bottom:0;
left:0;
width:250px;
height:64px;
background:rgba(0,0,0,0.5);
color:white;
}
.accd li.on{
height:464px;
}-
JS
首先定義高度和初始化各項圖片,并給第一張加上on
,以表示當前顯示圖片。$(function() { //define init shrink height and extn height var shrink_height = 64, extend_height = 464; //the accd container var $acc = $(".accd"); //the accd items var $acc_item = $acc.find("li"); //set the first item as the current $acc_item.first().addClass("on"); //set the height of the acc container $acc.css({ height: $acc_item.length * shrink_height + extend_height }); //init each accd item height and z-index $acc_item.each(function(i, v) { //init item state var $that = $(this); //calc the top value of each item var idx = $(this).index(); var t = idx * shrink_height; //set the initiate top value and z-index to each item $(this).css({ top: t, 'z-index': ($acc_item.length - idx) }); //bind event listener to mouse over $(this).mouseenter(function() { //get the current item idx var i = $(this).index(); var i_on = $(".on").index(); //make sure that only move the items that are not on the current stage if (!$that.hasClass("on")) { //change on class $(this).addClass("on").siblings().removeClass("on"); /* * calculate which items to move */ var diff = (i - i_on); if (diff > 0) { accUp(i_on, diff); } else if (diff < 0) { accDown(i, Math.abs(diff)); } } }); }); //move up the acc items function accUp(i, count) { var $item = $($acc_item.get().splice(i, count)); $item.each(function(i, v) { $(v).animate({ top: '-=400' }, 100); }); } //move down the acc items function accDown(i, count) { var $item = $($acc_item.get().splice(i, count)); $item.each(function(i, v) { $(v).animate({ top: '+=400' }, 100); }); } });
其中accUp和accDown為向上和向下移動一定數量的圖片,需要注意的是:如果向上移動需要從on
那一張往前算起;而想下移動則需要從鼠標指向的的那一張向下開始算起。