滑動展示效果主要用在圖檔或資訊的滑動展示,也可以設定一下做成簡單的口風琴(accordion)效果。
這個其實就是以前寫的圖檔滑動展示效果 的改進版,那是我第一篇比較受關注的文章,是時候整理一下了。
有如下特色:
1,有四種方向模式選擇;
3,能自動根據滑動元素計算展示尺寸;
4,也可自定義展示或收縮尺寸;
5,可擴充自動切換功能;
6,可擴充滑動提示功能。
相容:ie6/7/8, firefox 3.6.8, opera 10.51, safari 4.0.5, chrome 5.0
程式說明
【基本原理】
通過設定滑動元素的位置坐标(left/right/top/bottom),實作滑鼠進入的目标元素滑動展示,其他元素滑動收縮的效果。
難點是如何控制多個滑動元素同時進行不同的滑動,這裡關鍵就在于把整體滑動分解成各個滑動元素進行各自的滑動。
方法是給各個滑動元素設定目标值,然後各自向自己的目标值滑動,當全部都到達目标值就完成了。
【容器設定】
在_initcontainer方法中進行容器設定,由于後面滑動參數的計算要用到容器,是以要先設定容器。
先設定容器樣式,要實作滑動需要設定容器相對或絕對定位,并且設定overflow為"hidden"來固定容器大小,而滑動元素也要設定絕對定位。
滑鼠移出容器時會觸發_leave移出函數:

$$e.addevent( container, "mouseleave", this._leave );
其中_leave函數是這樣的:

var close = $$f.bind( this.close, this );
this._leave = $$f.bind( function(){
cleartimeout(this._timerdelay);
$$ce.fireevent( this, "leave" );
if ( this.autoclose ) { this._timerdelay = settimeout( close, this.delay ); }
}, this );
當autoclose屬性為true時才會延時觸發close方法。
【滑動對象】
程式初始化時會根據滑動元素建立滑動對象集合。
先擷取滑動元素:

var nodes = opt.nodes ? $$a.map( opt.nodes, function(n) { return n; } )
: $$a.filter( container.childnodes, function(n) { return n.nodetype == 1; });
如果沒有自定義nodes滑動元素,就從容器擷取childnodes作為滑動元素。
還要用nodetype篩選一下,因為ie外的浏覽器都會把空格作為childnodes的一部分。
接着用擷取的滑動元素生成程式需要的_nodes滑動對象集合:

this._nodes = $$a.map( nodes, function(node){ return { "node": node }; });
滑動對象用"node"屬性記錄滑動元素。
然後在_initnodes方法中初始化滑動對象。
每個滑動對象都有3個用來計算滑動目标值的屬性:defaulttarget預設目标值,max展示尺寸,min收縮尺寸。
如果有自定義max尺寸或min尺寸,會根據自定義的尺寸來計算。
程式會優先按max來計算:

max = math.max( max <= 1 ? max * clientsize : math.min( max, clientsize ), defaultsize );
min = ( clientsize - max ) / maxindex;
其中clientsize是容器的可見區域尺寸,defaultsize是平均配置設定尺寸。
如果max是小數或1就按百分比計算,再把尺寸限制在defaultsize到clientsize的範圍内。
再計算減去max後其他收縮元素的平均尺寸,就可以得到min了。
如果沒有自定義max再按自定義min來計算:

min = math.min( min < 1 ? min * clientsize : min, defaultsize );
max = clientsize - maxindex * min;
同樣,如果min是小數就按百分比計算,再做範圍限制,然後計算得出max。最後得到自定義尺寸計算函數:

getmax = function(){ return max; };
getmin = function(){ return min; };
如果沒有自定義max或min,就根據元素尺寸來計算:

getmax = function(o){ return math.max( math.min( o.node[ offset ], clientsize ), defaultsize ); };
getmin = function(o){ return ( clientsize - o.max ) / maxindex; };
把元素尺寸作為展示尺寸來計算,同樣要做範圍限制,然後計算收縮尺寸。
得到尺寸計算函數後,再用_each方法曆遍并設定滑動對象:

o.current = o.defaulttarget = getdefaulttarget(i);
o.max = getmax(o); o.min = getmin(o);
其中current是目前坐标值,在移動計算時作為開始值的。
而defaulttarget是預設目标值,即預設狀态時移動的目标值,根據defaultsize和索引得到。
還要設定當滑鼠進入滑動元素時觸發show展示函數:

var node = o.node, show = $$f.bind( this.show, this, i );
o.show = $$f.bind( function(){
this._timerdelay = settimeout( show, this.delay );
$$ce.fireevent( this, "enter", i );
$$e.addevent( node, "mouseenter", o.show );
要在滑動元素的"mouseenter"事件中觸發,并傳遞目前滑動對象的索引,再加上延時設定就可以了。
【滑動展示】
當滑鼠進入其中一個滑動元素,就會觸發show方法開始展示。
首先執行_setmove方法設定滑動參數,并以索引作為參數。
在_setmove裡面主要是設定計算移動值時需要的目标值、開始值和變化值。
先修正索引,錯誤的索引值會設定為0:

this._index = index = index < 0 || index > maxindex ? 0 : index | 0;
再根據索引擷取要展示的滑動對象,通過展示對象的min和max得到gettarget目标值函數:

var nodeshow = nodes[ index ], min = nodeshow.min, max = nodeshow.max;
gettarget = function(o, i){ return i <= index ? min * i : min * ( i - 1 ) + max; };
如果滑動對象就是展示對象或者在展示對象前面,目标值就是min * i,因為第i+1個滑動對象的目标值就是i個min的大小。
否則,目标值就是min * ( i - 1 ) + max,其實就是把展示對象的位置換成max。
然後設定每個滑動對象的參數屬性:

this._each( function(o, i){
o.target = gettarget(o, i);
o.begin = o.current;
o.change = o.target - o.begin;
});
其中target記錄目标值,begin通過current得到開始值,目标值和開始值的差就是change改變值。
設定完成後,就執行_easemove方法開始滑移,在裡面重置_time屬性為0,再就執行_move程式就正式開始移動了。
首先判斷_time是否到達duration持續時間,沒有到達的話,就繼續移動。
程式設定了一個_tweenmove移動函數,用來設定緩動:

this._setpos( function(o) {
return this.tween( this._time, o.begin, o.change, this.duration );
});
利用tween算法,結合目前時間,開始值,改變值和持續時間,就能得到目前要移動的坐标值。
ps:關于tween緩動可以參考tween算法及緩動效果 。
當_time到達duration說明滑動已經完成,再執行一次_targetmove目标值移動函數:

this._setpos( function(o) { return o.target; } );
直接移動到目标值,可以防止可能出現的計算誤差導緻移位不準确。
【關閉和重置】
close方法可以關閉展示,即滑動到預設狀态,預設在移出容器時就會執行。
預設狀态是指全部滑動元素位于defaulttarget預設目标值的狀态。
先用_setmove設定移動參數,當_setmove沒有索引參數時,就會設定目标值為預設目标值:

gettarget = function(o){ return o.defaulttarget; }
完成參數設定後,再執行_easemove進行滑動,跟滑動展示類似。
reset方法可以重置展示,重置的意思是不進行滑動而直接移動到目标值。
如果沒有索引參數,就會直接執行_defaultmove預設值移動函數:

this._setpos( function(o) { return o.defaulttarget; } );
直接把滑動元素移動到預設狀态。
如果有索引參數,就先用_setmove根據索引設定目标值,再執行_targetmove直接移動到目标值。
程式初始化後會執行一次reset,并且以自定義defaultindex作為參數。
利用defaultindex可以一開始就展示對應索引的滑動對象。
【方向模式】
程式可以自定義mode方向模式,有四種方向模式:bottom、top、right、left(預設)。
其中right和left是在水準方向滑動,而bottom和top是在垂直方向滑動。
而right和left的差別是定點方向不同,left以左邊為定點在右邊滑動,right就相反。
具體參考執行個體就應該明白了,bottom和top的差別也類似。
程式是通過對不同的方向就修改對應方向的坐标樣式來實作的。
例如left模式就用"left"樣式來做移動效果,top模式就用"top"樣式。
初始化程式中設定的_pos屬性就是用來記錄目前模式要使用的坐标樣式的:

this._pos = /^(bottom|top|right|left)$/.test( opt.mode.tolowercase() ) ? regexp.$1 : "left";
然後在_setpos方法中使用_pos指定的坐标樣式來設定坐标值:

var pos = this._pos;
this._each( function(o, i) {
o.node.style[ pos ] = (o.current = math.round(method.call( this, o ))) + "px";
而_horizontal屬性就記錄了是否水準方向滑動,即是否right或left。
在計算尺寸時,通過它來指定使用用水準還是垂直方向的尺寸。
還有一個_reverse屬性,判斷是否bottom或right模式。
這個屬性是為了解決一個問題,例如right模式要實作類似下面的效果:
有兩種方法,可以調整元素插入順序:

<div class="container">
<div style="right:0;">2</div>
<div style="right:100px;">1</div>
<div style="right:200px;">0</div>
</div>
但這樣需要修改dom結構,或者通過zindex設定堆疊順序:

<div style="right:200px;z-index:3;">0</div>
<div style="right:100px;z-index:2;">1</div>
<div style="right:0;z-index:1;">2</div>
顯然設定zindex的方法比較好,程式也用了這個方法。
程式就是用_reverse屬性來判斷是否需要做這些修正。
首先在_initcontainer中,根據_reverse重新設定zindex:

var zindex = 100, gradient = this._reverse ? -1 : 1;
this._each( function(o){
var style = o.node.style;
style.position = "absolute"; style.zindex = zindex += gradient;
在_initnodes中,擷取預設目标值時也要判斷:

getdefaulttarget = this._reverse
? function(i){ return defaultsize * ( maxindex - i ); }
: function(i){ return defaultsize * i; },
當_reverse為true時,由于定點位置是在索引的反方向,設定元素時也應該倒過來設的,是以要用maxindex減一下。
在_setmove中,根據索引設定滑動目标值時,也要判斷:

if ( this._reverse ) {
var get = gettarget;
index = maxindex - index;
gettarget = function(o, i){ return get( o, maxindex - i ); }
}
不但滑動對象集合的索引要修正,展示對象的索引也要修正。
【自動展示擴充】
這次擴充用的是組合模式,原理參考的imagezoom擴充篇的擴充模式部分 。
不同的是加了一個屬性擴充,用來添加擴充方法:

$$.extend( this, prototype );
注意不能添加到slideview.prototype,這樣會影響到slideview的結構。
“自動展示”要實作的是滑動對象自動輪流展示,并且取消預設狀态而實行強制展示,可以用在圖檔的輪換展示。
隻要在slideview後面加入自動展示擴充程式,并且auto參數設為true就會啟用。
原理也很簡單,就是每次滑動/移動完成後,用定時器執行下一次滑動就行了。
首先在"init"初始化程式中,增加一個_next程式,用來展示下一個滑動對象:

this._next = $$f.bind( function(){ this.show( this._index + 1 ); }, this );
其實就是把目前索引_index加1之後作為show的參數執行。
再增加一個_autonext方法:

if ( !this._autopause ) {
cleartimeout(this._autotimer);
this._autotimer = settimeout( this._next, this.autodelay );
作用是延時執行_next程式,并且有一個_autopause屬性用來鎖定執行。
然後設定幾個需要執行的地方。
首先在"finish"完成滑動事件中,執行_autonext方法,這樣就實作了基本的自動展示了。
在滑鼠進入滑動元素後,應該停止自動切換,是以在"enter"進入滑動元素事件中,會清除定時器并把_autopause設為true來鎖定。
對應地在"leave"滑鼠離開容器事件中,要把_autopause設回false解除鎖定,再執行_autonext方法重新啟動自動程式。
并且在"leave"中設定autoclose為false,防止自動恢複預設狀态。
最後還要重寫reset:

reset.call( this, index == undefined ? this._index : index );
this._autonext();
重寫後的reset會強制設定索引來展示,并執行_autonext進行下一次滑動。
【提示資訊擴充】
“提示資訊”效果是指每個滑動對象對應有一個提示資訊(内容)的層(元素)。
這個提示資訊會在滑動對象展示時展示,收縮和關閉時關閉。
隻要加入提示資訊擴充程式,并且tip參數設為true就會啟用。
提示擴充支援四種位置提示:bottom、top、right、left。
在"init"中,根據自定義tipmode擷取_tippos坐标樣式:

this._tippos = /^(bottom|top|right|left)$/.test( this.options.tippos.tolowercase() ) ? regexp.$1 : "bottom";
接着在"initnodes"定義一個能根據滑動元素擷取提示元素的函數:

var opt = this.options, tiptag = opt.tiptag, tipclass = opt.tipclass,
re = tipclass && new regexp("(^|\\s)" + tipclass + "(\\s|$)"),
gettipnode = function(node){
var nodes = node.getelementsbytagname( tiptag );
if ( tipclass ) {
nodes = $$a.filter( nodes, function(n){ return re.test(n.classname); } );
}
return nodes[0];
};
如果自定義了tiptag,就會根據标簽來擷取元素,否則就按預設值"*"擷取全部元素。
如果自定義了tipclass,就會再根據classname來篩選元素,注意可能包含多個樣式,不能直接等于。
得到函數後,再建立提示對象:

this._each( function(o) {
var node = o.node, tipnode = gettipnode(node);
node.style.overflow = "hidden";
tipnode.style.position = "absolute"; tipnode.style.left = 0;
o.tip = {
"node": tipnode,
"show": tipshow != undefined ? tipshow : 0,
"close": tipclose != undefined ? tipclose : -tipnode[offset]
先擷取提示元素,并設定相關樣式,再給滑動對象添加一個tip屬性,儲存對應的提示對象。
其中"node"屬性儲存提示元素,"show"是展示時的坐标值,"close"是關閉時的坐标值。
如果沒有自定義tipshow,預設展示時坐标值是0,即提示元素剛好貼在滑動元素邊上的位置;
如果沒有自定義tipclose,預設關閉時坐标是提示元素的尺寸,即提示元素剛好隐藏在滑動元素外面的位置。
在"setmove"中設定提示移動目标值:

var maxindex = this._nodes.length - 1;
var tip = o.tip;
if ( this._reverse ) { i = maxindex -i; }
tip.target = index == undefined || index != i ? tip.close : tip.show;
tip.begin = tip.current; tip.change = tip.target - tip.begin;
這個比滑動對象的設定簡單得多,當設定了index參數,并且index等于該滑動對象的索引時才需要展示,其他情況都是隐藏。
要注意,跟滑動對象一樣,在_reverse為true的時候需要修正索引。
在"tweenmove"、"targetmove"、"defaultmove"也要設定對應的移動函數。
為了友善樣式設定,擴充了一個_settippos方法:

var pos = this._tippos;
tip.node.style[ pos ] = (tip.current = method.call( this, tip )) + "px";
根據_tippos坐标樣式來設定坐标值。
使用技巧
【展示尺寸】
要自定義展示尺寸可以通過max和min來設定,可以按像素或百分比來計算。
如果不設定的話,就會按照元素本身的尺寸來展示。
是以滑動元素展示的尺寸并不需要一緻的,程式可以自動計算。
【accordion效果】
accordion是可折疊的面闆控件,效果類似手風琴,slideview通過設定也能做到類似的效果。
首先把autoclose設為false取消自動關閉,再設定defaultindex,使slideview處于展開狀态不會關閉。
一般accordion都有一個固定尺寸的标題,這個可以用min來設定。
這樣就實作了簡單的accordion效果,具體參考第三個執行個體。
使用說明
執行個體化時,必須有容器對象或id作為參數:

new slideview( "idslideview" );
可選參數用來設定系統的預設屬性,包括:
屬性: 預設值//說明
nodes: null,//自定義展示元素集合
mode: "left",//方向
max: 0,//展示尺寸(像素或百分比)
min: 0,//收縮尺寸(像素或百分比)
delay: 100,//觸發延時
interval: 20,//滑動間隔
duration: 20,//滑動持續時間
defaultindex: null,//預設展示索引
autoclose: true,//是否自動恢複
tween: function(t,b,c,d){ return -c * ((t=t/d-1)*t*t*t - 1) + b; },//tween算子
onshow: function(index){},//滑動展示時執行
onclose: function(){}//滑動關閉執行
其中interval、delay、duration、tween、autoclose、onshow、onclose屬性可以在程式初始化後動态設定。
還提供了以下方法:
show:根據索引滑動展示;
close:滑動到預設狀态;
reset:重置為預設狀态或展開索引對應滑動對象;
dispose:銷毀程式。
要使用自動展示,隻要在slideview後面加入自動展示擴充程式,并且auto參數設為true即可。
新增如下可選參數:
autodelay: 2000//展示時間
要使用提示資訊,隻要加入提示資訊擴充程式,并且tip參數設為true即可。
tippos: "bottom",//提示位置
tiptag: "*",//提示元素标簽
tipclass: "",//提示元素樣式
tipshow: null,//展示時目标坐标
tipclose: null//關閉時目标坐标