自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Slider實(shí)現(xiàn)的滑動(dòng)條效果

開(kāi)發(fā) 前端
在做了拖放效果之后,我想應(yīng)該可以做一個(gè)更好的了,所以重做一遍,完善和擴(kuò)展了一些功能。礙于時(shí)間沒(méi)有做得很強(qiáng)大,都是一些基本功能,希望各位多提意見(jiàn)!

這個(gè)滑動(dòng)條(拖動(dòng)條)效果,一開(kāi)始是參考了BlueDestiny的slider和Apple產(chǎn)品展示的樣式,做了程序的原型。

在做了拖放效果之后,我想應(yīng)該可以做一個(gè)更好的了,所以重做一遍,完善和擴(kuò)展了一些功能。礙于時(shí)間沒(méi)有做得很強(qiáng)大,都是一些基本功能,希望各位多提意見(jiàn)!

效果預(yù)覽

預(yù)覽效果1:

這個(gè)是仿Apple滑動(dòng)條產(chǎn)品展示效果。

除了原來(lái)的效果(包括點(diǎn)擊緩動(dòng)滑移、拖動(dòng)滑移),我還加入了本程序特有的滾輪和鍵盤(pán)控制,滑動(dòng)條兩端鼠標(biāo)放上去會(huì)自動(dòng)滑動(dòng),滑動(dòng)到兩邊還會(huì)自動(dòng)換一個(gè)表示停止的圖案。

[[79388]]

預(yù)覽效果2:

這里是稍微模擬了一下滾動(dòng)條,當(dāng)然離真正的滾動(dòng)條還差很遠(yuǎn)。

滑動(dòng)條除了水平還支持垂直方向的滑動(dòng),在內(nèi)容顯示部分按上下方向(需要先點(diǎn)擊選中一下)或使用鼠標(biāo)滾輪也能控制滑動(dòng)。

 

預(yù)覽效果3:

這里主要是滑動(dòng)條關(guān)于值方面的應(yīng)用,可以應(yīng)用在度量計(jì)算等方面。

圖片已經(jīng)帶我們大致了解了這個(gè)效果,下面請(qǐng)我們耐心的看一下程序說(shuō)明。

#p#

程序說(shuō)明

首先需要一個(gè)容器,滑動(dòng)范圍就在這個(gè)容器里面,還有是容器里面的絕對(duì)定位的滑塊,基本就是這兩部分。

滑塊拖放的部分請(qǐng)參考拖放效果,這里我把拖放程序擴(kuò)展了一個(gè)設(shè)置滑塊位置的SetPos方法方便程序使用。

【水平和垂直滑動(dòng)】

程序支持水平和垂直滑動(dòng),設(shè)置Horizontal屬性為true就是水平滑動(dòng)(默認(rèn)),為false就是垂直滑動(dòng)。這個(gè)屬性只能在實(shí)例化時(shí)設(shè)置,初始化之后會(huì)就不要修改了。

程序初始化時(shí)就根據(jù)這個(gè)屬性鎖定拖放的方向:

  1. this._drag[this._horizontal ? "LockY" : "LockX"] = true;  

程序支持兩個(gè)方向的滑動(dòng),如果每次都判斷一下再分別設(shè)置參數(shù)會(huì)很麻煩,所以程序中每次滑動(dòng)都計(jì)算兩個(gè)方向的位置參數(shù),并把參數(shù)直接交給_drag來(lái)處理。
由于_drag在實(shí)例化時(shí)已經(jīng)做了范圍限制和方向鎖定,已經(jīng)帶了位置參數(shù)修正,所以可以直接交給它處理。

這樣雖然效率差點(diǎn),但就能大大降低復(fù)雜度,我想還是值得的。

【自動(dòng)滑移】

運(yùn)行Run自動(dòng)滑移程序后,就會(huì)自動(dòng)滑移,參數(shù)可以設(shè)置滑移的方向(true為右/下,false為左/上)。

步長(zhǎng)是根據(jù)百分比來(lái)設(shè)置的

  1. var percent = this.GetPercent() + (bIncrease ? 1 : -1) * this.RunStep / 100;  
  2. this.SetPos((this.Container.clientWidth - this.Bar.offsetWidth) * percent, (this.Container.clientHeight - this.Bar.offsetHeight) * percent);  

然后通過(guò)位置屬性判斷是否到了極限值,不是的話(huà)就用一個(gè)定時(shí)器繼續(xù)滑動(dòng):

  1. if(!(bIncrease ? this._IsMax : this._IsMin)){  
  2.     this._timer = setTimeout(Bind(thisthis.Run, bIncrease), this.RunTime);  
  3. }  

【緩動(dòng)滑移】

除了SetPos還有一個(gè)EasePos緩動(dòng)滑移程序可以設(shè)置滑塊位置。

如果Ease屬性是false時(shí),EasePos跟SetPos一樣直接設(shè)置位置,為true時(shí)就會(huì)緩動(dòng)(減速)設(shè)置位置。

其中緩動(dòng)的效果請(qǐng)參考圖片切換展示效果 ,程序中如果目標(biāo)值超過(guò)極限值時(shí)不能直接判斷是否到達(dá)目標(biāo)值,不過(guò)可以用_IsMid屬性(參考位置判斷部分)來(lái)判斷沒(méi)有到極限值。

注意,因?yàn)橐鷒ffset取的值比較,而offset取的值是整數(shù),所以參數(shù)必須轉(zhuǎn)換成整數(shù)(程序用Math.round處理了),否則如果是小數(shù)那就永遠(yuǎn)都不會(huì)相等(死循環(huán))了。

ps:程序只在鼠標(biāo)點(diǎn)擊控制和設(shè)置百分比位置中使用了EasePos,其它情況比較適合用SetPos。

#p#

【百分比和值】

這個(gè)是基本功能了,先看看GetPercent獲取百分比程序,這個(gè)百分比就是滑塊左邊距離跟滑動(dòng)區(qū)域的比例:

  1. return this._horizontal ? this.Bar.offsetLeft / (this.Container.clientWidth - this.Bar.offsetWidth)  
  2.         : this.Bar.offsetTop / (this.Container.clientHeight - this.Bar.offsetHeight)  

注意滑動(dòng)區(qū)域是容器的clientWidth減去滑塊的offsetWidth(關(guān)于這兩個(gè)屬性詳細(xì)請(qǐng)看這里)。

對(duì)應(yīng)的有SetPercent設(shè)置百分比位置程序,就是根據(jù)百分比參數(shù)設(shè)置滑塊的位置:

  1. this.EasePos((this.Container.clientWidth - this.Bar.offsetWidth) * value, (this.Container.clientHeight - this.Bar.offsetHeight) * value); 

滑動(dòng)條更多的應(yīng)用是在于值的運(yùn)用。程序中屬性MinValue和MaxValue分別設(shè)置最小值和最大值。

ps:雖然說(shuō)是最大值,但不一定就比較大的,不過(guò)這樣寫(xiě)起來(lái)比較方便。

當(dāng)設(shè)置了這兩個(gè)屬性(值)就能GetValue獲取當(dāng)前值了:

  1. return this.MinValue + this.GetPercent() * (this.MaxValue - this.MinValue);  

對(duì)應(yīng)的SetValue設(shè)置值位置程序:

  1. this.SetPercent((value- this.MinValue)/(this.MaxValue - this.MinValue));  

這個(gè)很簡(jiǎn)單,懂點(diǎn)數(shù)學(xué)應(yīng)該都明白了。

【位置狀態(tài)】

程序中有位置程序onMin(最小值時(shí))、onMax(最大值時(shí))和onMid(中間值時(shí))分別在各自位置時(shí)執(zhí)行。

ps:onMid指的是除最小值最大值外的中間部分,不是中心值。

程序是在Move滑動(dòng)程序中通過(guò)百分比來(lái)判斷當(dāng)前位置的(0時(shí)為最小值,1時(shí)為最大值,其他為中間值)。

由于Move程序并不會(huì)因?yàn)榈搅藰O限值就停止,如果僅僅根據(jù)百分比來(lái)判斷那么到了極限值,值雖然不變但程序就會(huì)一直被觸發(fā)。

而我需要的是當(dāng)值不變的時(shí)候,對(duì)應(yīng)位置程序僅僅觸發(fā)一次。根據(jù)需求就衍生出三個(gè)位置狀態(tài)屬性_IsMin(最小值狀態(tài))、_IsMax(最大值狀態(tài))和_IsMid(中間值狀態(tài))。

用這幾個(gè)狀態(tài)屬性和百分比就能實(shí)現(xiàn)需要的效果了:

  1. var percent = this.GetPercent();  
  2. //最小值判斷  
  3. if(percent > 0){  
  4.     this._IsMin = false;  
  5. }else{  
  6.     if(!this._IsMin){ this.onMin(); this._IsMin = true; }  
  7. }  
  8. //最大值判斷  
  9. if(percent < 1){  
  10.     this._IsMax = false;  
  11. }else{  
  12.     if(!this._IsMax){ this.onMax(); this._IsMax = true; }  
  13. }  
  14. //中間值判斷  
  15. if(percent > 0 && percent < 1){  
  16.     if(!this._IsMid){ this.onMid(); this._IsMid = true; }  
  17. }else{  
  18.     this._IsMid = false;  
  19. }  

這三個(gè)位置狀態(tài)屬性在其他程序中也用來(lái)判斷是否到了極限值。

#p#

【鼠標(biāo)拖動(dòng)控制】

鼠標(biāo)拖動(dòng)控制,就是通過(guò)拖動(dòng)滑塊來(lái)設(shè)置定位。

這個(gè)就跟滾動(dòng)條意思差不多,主要是通過(guò)_drag本身的拖放效果來(lái)實(shí)現(xiàn)的(詳細(xì)看這里拖放效果)。

【鼠標(biāo)點(diǎn)擊控制】

鼠標(biāo)點(diǎn)擊控制,就是當(dāng)點(diǎn)擊容器的時(shí)候能定位到點(diǎn)擊的位置。

一般來(lái)說(shuō)只要把ClickCtrl鼠標(biāo)點(diǎn)擊控制程序綁定容器的click事件中就可以了。

但這里有個(gè)問(wèn)題,滑塊的點(diǎn)擊(拖動(dòng)控制)跟容器的點(diǎn)擊會(huì)發(fā)生沖突,具體表現(xiàn)是拖放結(jié)束后就“順便”觸發(fā)了容器的click。

這個(gè)本來(lái)在滑塊的點(diǎn)擊事件中取消冒泡就可以:

  1. addEventHandler(this.Bar, "click", BindAsEventListener(thisfunction(e){ e.stopPropagation(); }));  

但ie的click機(jī)制有點(diǎn)問(wèn)題:

  1. <div style="width:100px; height:100px; background-color:#CCC;" onclick="alert(1)" > 
  2. <div style=" height:50px; background-color:#C11;" onclick="event.stopPropagation?event.stopPropagation():(event.cancelBubble=true);" ></div> 
  3. </div> 

里面的div取消冒泡,點(diǎn)擊它不會(huì)觸發(fā)外面div的onclick,但如果在里面的div點(diǎn),然拖動(dòng)到外面的div放,就會(huì)觸發(fā)了,而ff是不會(huì)的。

ps:從外面拖到里面也是一樣的情況。

經(jīng)過(guò)測(cè)試,我覺(jué)得是因?yàn)閕e認(rèn)為點(diǎn)擊的點(diǎn)和放只要是發(fā)生在同一個(gè)元素的內(nèi)部(包括內(nèi)部的其他元素),那個(gè)這個(gè)點(diǎn)擊就是有效的;而ff則認(rèn)為點(diǎn)擊的點(diǎn)和放必須在同一個(gè)元素內(nèi)才有效(w3c標(biāo)準(zhǔn)應(yīng)該也是這樣)。

這個(gè)導(dǎo)致的問(wèn)題是,當(dāng)拖放結(jié)束時(shí)如果放開(kāi)鼠標(biāo)的地方是容器上,那么就會(huì)發(fā)生沖突了。

那對(duì)于ie的這個(gè)現(xiàn)象,解決方法其實(shí)也很多,我用的方法很簡(jiǎn)單,設(shè)一個(gè)屬性_ondrag來(lái)表示是否拖放中。

具體就是在DragStart開(kāi)始拖放滑動(dòng)程序中把_ondrag設(shè)為true,并在DragStop結(jié)束拖放滑動(dòng)程序中把它設(shè)為false:

  1. setTimeout(Bind(thisfunction(){ this._ondrag = false; }), 10);  

這里用了setTimeout,因?yàn)橥戏沤Y(jié)束后才會(huì)觸發(fā)容器的click,所以設(shè)一個(gè)延時(shí),使這個(gè)值在容器的click觸發(fā)后才修改。

這樣就可以通過(guò)這個(gè)_ondrag來(lái)判斷是否應(yīng)該執(zhí)行ClickCtrl了:

  1. addEventHandler(this.Container, "click", BindAsEventListener(this, function(e){ this._ondrag || this.ClickCtrl(e);}));  

接著看ClickCtrl鼠標(biāo)點(diǎn)擊控制程序,首先獲取容器的相對(duì)文檔的位置:

  1. var o = this.Container, iLeft = o.offsetLeft, iTop = o.offsetTop;  
  2. while (o.offsetParent) { o = o.offsetParent; iLeft += o.offsetLeft; iTop += o.offsetTop; }  

注意,要逐級(jí)向上獲取才能取得相對(duì)相對(duì)文檔的位置。

然后通過(guò)pageX(pageY)和滑塊(這里是要設(shè)置到滑塊的中間位置所以取一半)得到要設(shè)置的位置:

  1. this.EasePos(e.pageX - iLeft - this.Bar.offsetWidth / 2, e.pageY - iTop - this.Bar.offsetHeight / 2);  

這里要用pageX(pageY)來(lái)取值,而不是clientX(clientY),因?yàn)楹笳呤菦](méi)有計(jì)算滾動(dòng)條的。

ps:ie沒(méi)有pageX(pageY),不過(guò)在Event程序中已經(jīng)給window.event添加了這個(gè)屬性:

  1. oEvent.pageX = oEvent.clientX + document.documentElement.scrollLeft;  
  2. oEvent.pageY = oEvent.clientY + document.documentElement.scrollTop;  

【鼠標(biāo)滾輪控制】

鼠標(biāo)滾輪控制,就是通過(guò)鼠標(biāo)滾輪滾動(dòng)來(lái)控制滑塊的滑動(dòng)。

首先ie綁定滾輪事件用的是mousewheel,ff用的是DOMMouseScroll,所以在WheelBind綁定鼠標(biāo)滾輪程序中是這樣設(shè)置的:

  1. addEventHandler(o, isIE ? "mousewheel" : "DOMMouseScroll", BindAsEventListener(thisthis.WheelCtrl));  

接著看WheelCtrl鼠標(biāo)滾輪控制程序,通過(guò)event的detail屬性可以獲取鼠標(biāo)滾動(dòng)的距離(值大?。┖头较颍ㄕ?fù))。

利用它來(lái)設(shè)置要滑動(dòng)的位置:

  1. var i = this.WheelSpeed * e.detail;  
  2. this.SetPos(this.Bar.offsetLeft + i, this.Bar.offsetTop + i);  

但ie沒(méi)有detail,對(duì)應(yīng)的有wheelDelta,wheelDelta的數(shù)值剛好是detail的40倍,而且方向相反(正負(fù)相反),所以Event程序中是這樣給window.event添加detail的:

  1. oEvent.detail = oEvent.wheelDelta / (-40);  

為了防止觸發(fā)其他滾動(dòng)條,這里用了preventDefault取消默認(rèn)動(dòng)作。

注意不是用取消冒泡(貌似滾屏是事件的默認(rèn)動(dòng)作)。

【方向鍵控制】

方向鍵控制,就是通過(guò)鍵盤(pán)的左右(上下)方向鍵來(lái)控制滑塊的滑動(dòng)。

首先用KeyBind方向鍵綁定程序把KeyCtrl方向鍵控制程序綁定到對(duì)象的keydown事件中:

  1. addEventHandler(o, "keydown", BindAsEventListener(thisthis.KeyCtrl));  

在KeyCtrl中,通過(guò)event的keyCode屬性獲取鍵盤(pán)的按鍵(左37、上38、右39、下40)并進(jìn)行相應(yīng)的操作:

  1. switch (e.keyCode) {  
  2.     case 37 ://左  
  3.         iLeft -= iWidth; break;  
  4.     case 38 ://上  
  5.         iTop -= iHeight; break;  
  6.     case 39 ://右  
  7.         iLeft += iWidth; break;  
  8.     case 40 ://下  
  9.         iTop += iHeight; break;  
  10.     default :  
  11.         return;//不是方向按鍵返回  
  12. }  

同樣為了防止觸發(fā)其他滾動(dòng)條,也用了preventDefault取消默認(rèn)動(dòng)作。

 #p#

【focus和tabIndex】

在KeyBind程序中,除了綁定對(duì)象的keydown事件,還不夠的,可以在ff測(cè)試下面的代碼:

  1. <div style="width:100px; height:100px; background-color:#CCC;" onkeydown="alert(1)"></div>  

無(wú)論怎樣都觸發(fā)不了onkeydown事件(ie可以觸發(fā)),那就奇怪了,按照一般的思路應(yīng)該是可以的啊。

這個(gè)可以從w3c關(guān)于KeyboardEvent的部分中找到原因:Keyboard events are commonly directed at the element that has the focus.大概就是說(shuō)鍵盤(pán)按鍵事件一般指向能獲取焦點(diǎn)的元素,就是不能獲取焦點(diǎn)的元素就不能觸發(fā)鍵盤(pán)按鍵事件了。

難道div就不能獲取焦點(diǎn)?用下面的代碼測(cè)試(ff):

  1. <div id="test" style="width:100px; height:100px; background-color:#CCC;" onfocus="alert(1)"></div>  
  2. <script>document.getElementById("test").focus();</script>  

還真的不行,那問(wèn)題就在于怎么使div能獲取焦點(diǎn)了(當(dāng)然這個(gè)是轉(zhuǎn)了不少?gòu)澆畔氤鰜?lái)的)。

最后發(fā)現(xiàn)給元素設(shè)置tabIndex就能讓元素能獲取焦點(diǎn)了,如果不需要詳細(xì)了解的話(huà)下面可以略過(guò)。

首先看看w3c關(guān)于onfocus的部分:The onfocus event occurs when an element receives focus either by the pointing device or by tabbing navigation.
This attribute may be used with the following elements: A, AREA, LABEL, INPUT, SELECT, TEXTAREA, and BUTTON. 當(dāng)元素通過(guò)指定(點(diǎn)擊)或tab導(dǎo)航(Tabbing navigation)獲得焦點(diǎn),onfocus事件就會(huì)觸發(fā)。

該屬性會(huì)使用在以下元素(就是說(shuō)默認(rèn)可以獲取焦點(diǎn)的元素):A, AREA, LABEL, INPUT, SELECT, TEXTAREA, and BUTTON.
測(cè)試下面的代碼:

  1. <a href="#" onfocus="alert(1)" onkeydown="alert(2)">focus</a>  

果然兩個(gè)事件都可以執(zhí)行。

接著看Tabbing navigation的部分:Those elements that do not support the tabindex attribute or support it and assign it a value of "0" are navigated next. These elements are navigated in the order they appear in the character stream. 這里看得不太明白,關(guān)鍵的意思是給元素設(shè)置tabindex為0就可以被導(dǎo)航到了(能獲取焦點(diǎn)了)。

測(cè)試下面的代碼(ff):

  1. <div tabindex="0" style="width:100px; height:100px; background-color:#CCC;" onfocus="alert(1)" onkeydown="alert(2)"></div>  

果然兩個(gè)事件都能觸發(fā)了。

不過(guò)w3c說(shuō)得很模糊,msdn上倒是很清楚:An element can have focus if the tabIndex property is set to any valid negative or positive integer.
Elements that receive focus can fire the onblur and onfocus events as of Internet Explorer 4.0, and the onkeydown, onkeypress, and onkeyup events as of Internet Explorer 5.

只要元素的tabIndex屬性設(shè)置成任何有效的整數(shù)那么該元素就能取得焦點(diǎn)。元素在取得焦點(diǎn)后就能觸發(fā)onblur,onfocus,onkeydown, onkeypress和onkeyup事件。

不同tabIndex值在tab order(Tabbing navigation)中的情況:Objects with a positive tabIndex are selected in increasing iIndex order and in source order to resolve duplicates.Objects with an tabIndex of zero are selected in source order. Objects with a negative tabIndex are omitted from the tabbing order.

tabIndex值是正數(shù)的對(duì)象根據(jù)遞增的值順序和代碼中的位置順序來(lái)被選擇;tabIndex值是0的對(duì)象根據(jù)在代碼中的位置順序被選擇;tabIndex值是負(fù)數(shù)的對(duì)象會(huì)被忽略。這個(gè)不知道是否符合標(biāo)準(zhǔn),但貌似ff跟ie是一樣的(不同的地方后面會(huì)說(shuō))。

那么設(shè)置一個(gè)負(fù)的tabIndex值應(yīng)該是最理想的了。

ps:如果對(duì)ff的tabindex有興趣的話(huà),推薦看看Test cases for tabindex bugs in Firefox,里面有更詳細(xì)更專(zhuān)業(yè)的分析。

那ie通過(guò)一開(kāi)始的測(cè)試,是不是就說(shuō)明不需要了呢?我們換一個(gè)元素測(cè)試:

  1. <ul style="width:100px; height:100px; background-color:#CCC;" onfocus="alert(1)" onkeydown="alert(2)"></ul>  

換成ul就又不能觸發(fā)事件了,怎么搞的。

再看看msdn,里面有一段:The following elements can have focus by default but are not tab stops. .略. applet, div, frameSet, span, table, td.下面的元素默認(rèn)能獲取焦點(diǎn)但不能tab導(dǎo)航:applet, div, frameSet, span, table, td.

看來(lái)ie真是“為程序員著想”,但其他元素總不能漏了啊,還是全部都設(shè)置tabIndex好了。

終于回到程序上來(lái),首先設(shè)置tabIndex:

  1. o.tabIndex = -1;  

ff元素獲得焦點(diǎn)后會(huì)出現(xiàn)一個(gè)虛線(xiàn)框,去掉會(huì)美觀一點(diǎn):

  1. isIE || (o.style.outline = "none");  

ps:如果tabIndex設(shè)為0或以上的話(huà)ie也會(huì)出現(xiàn)虛線(xiàn)框。

綁定了keydown之后,點(diǎn)擊一下容器(獲取焦點(diǎn))后就能用方向鍵控制方向了,但如果(沒(méi)有獲得焦點(diǎn)時(shí))點(diǎn)擊滑塊,還是觸發(fā)不了事件。

因?yàn)榛瑝K在拖動(dòng)效果中ie的鼠標(biāo)捕獲和ff的取消默認(rèn)動(dòng)作導(dǎo)致容器不能獲得焦點(diǎn),那手動(dòng)設(shè)置可以嗎?

是可以的,ff中就是直接在滑塊的mousedown事件中執(zhí)行容器的focus方法獲得焦點(diǎn)。

ie本來(lái)也是可以的,但ie中當(dāng)對(duì)象執(zhí)行focus方法時(shí),如果該對(duì)象有部分在滾動(dòng)條外就會(huì)自動(dòng)滾動(dòng)到適當(dāng)?shù)奈恢茫ㄟ€好點(diǎn)擊不會(huì)這樣)。

為了降低影響,程序中把滑塊也綁定了鍵盤(pán)控制,這樣點(diǎn)擊滑塊時(shí)只要執(zhí)行滑塊的focus方法獲得焦點(diǎn)就可以了:

  1. var oFocus = isIE ? (this.KeyBind(this.Bar), this.Bar) : this.Container;  
  2. addEventHandler(this.Bar, "mousedown"function(){ oFocus.focus(); });  

ps:由于focus并不會(huì)冒泡(w3c標(biāo)準(zhǔn)),所以不用擔(dān)心滑塊的focus導(dǎo)致容器獲得焦點(diǎn)。

ps2:w3c的文檔還真是難讀,還是msdn的易懂。

#p#

【樣式設(shè)置】

程序沒(méi)有對(duì)margin之類(lèi)的樣式進(jìn)行處理,所以盡量使用“干凈”的元素,如果用ul那些,請(qǐng)先“清理”好。

在仿Apple滑動(dòng)條產(chǎn)品展示效果中,像那樣橫排的展示,最好是放在table里才能保證不換行,否則就要放一個(gè)很長(zhǎng)很長(zhǎng)的副容器來(lái)放內(nèi)容。

里面還有一個(gè)樣式比較特別的,細(xì)心的話(huà)可以看到滑塊是突出了一個(gè)半圓,而且是剛好能嵌在兩端的。

這里主要是滑塊兩邊的兩個(gè)層(兩個(gè)半圓)使用了絕對(duì)定位,設(shè)置了負(fù)的位置值(左邊是負(fù)的left,右邊是負(fù)的right)。

還有就是到達(dá)兩端時(shí)對(duì)應(yīng)的層會(huì)自動(dòng)換一個(gè)背景圖,但其實(shí)是同一張圖:

[[79389]]

這里是用了變換背景圖位置的方法,這個(gè)方法也不新鮮了,這里要說(shuō)說(shuō)的是,雖然只是換垂直方向的坐標(biāo),但backgroundPositionY只是ie的方法,所以還是要用backgroundPosition。

#p#

【應(yīng)用技巧】

在仿Apple滑動(dòng)條產(chǎn)品展示效果中,可以看到MaxValue設(shè)成了內(nèi)容容器的scrollWidth和clientWidth之差:

  1. MaxValue: $("idContent").scrollWidth - $("idContent").clientWidth,  

其實(shí)這個(gè)值就是內(nèi)容容器scrollLeft的最大值,這樣在滑動(dòng)時(shí)要設(shè)置的內(nèi)容容器的scrollLeft剛好就是GetValue方法的值了(預(yù)覽效果2也一樣):

  1. onMove: function(){ $("idContent").scrollLeft = this.GetValue(); }  

預(yù)覽效果2中,滑塊的高度也特別設(shè)置過(guò):

  1. $("idBar2").style.height = $("idSlider2").clientHeight * Math.min($("idContent2").clientHeight / $("idContent2").scrollHeight, 1) - 4 + "px";  

其實(shí)就是使內(nèi)容跟內(nèi)容容器的高度之比等于滑塊跟滑動(dòng)容器之比,當(dāng)然這個(gè)比不能大于1,否則就滑塊高度就超過(guò)容器高度了,里面的4是邊框?qū)挾取?/p>

這樣的好處是滑塊會(huì)根據(jù)實(shí)際內(nèi)容自動(dòng)設(shè)置大小,就像一般的滾動(dòng)條,內(nèi)容越多滾動(dòng)條就越小,反之就越大,這利于用戶(hù)體驗(yàn)。

ps:仿Apple那個(gè)為了突出效果所以沒(méi)有設(shè)置,實(shí)際應(yīng)用中也應(yīng)該這樣設(shè)置一下。

預(yù)覽效果3中,從GetValue和GetPercent取得的數(shù)有可能是很長(zhǎng)的小數(shù),所以顯示時(shí)必須處理一下。

這里看到程序中parseInt使用了兩個(gè)參數(shù),而且第二個(gè)參數(shù)是10,是不是多余的呢?

不是的,因?yàn)槭謨?cè)上說(shuō)了:如果沒(méi)有提供,則前綴為 '0x' 的字符串被當(dāng)作十六進(jìn)制,前綴為 '0' 的字符串被當(dāng)作八進(jìn)制。所有其它字符串都被當(dāng)作是十進(jìn)制的。而對(duì)于手動(dòng)輸入的數(shù)字,前面加了個(gè)0也是很普通的情況,這樣無(wú)意間就會(huì)變成八進(jìn)制了。

#p#

使用說(shuō)明

首先實(shí)例化一個(gè)滑動(dòng)條對(duì)象,需要兩個(gè)參數(shù),分別是滑動(dòng)容器和滑塊(滑塊要在容器里面哦): 

  1. var sld = new Slider("idSlider""idBar")  

有以下這些可選參數(shù)和屬性: 

程序代碼

  1. //滑動(dòng)條程序  
  2. var Slider = Class.create();  
  3. Slider.prototype = {  
  4.   //容器對(duì)象,滑塊  
  5.   initialize: function(container, bar, options) {  
  6.     this.Bar = $(bar);  
  7.     this.Container = $(container);  
  8.     this._timer = null;//自動(dòng)滑移的定時(shí)器  
  9.     this._ondrag = false;//解決ie的click問(wèn)題  
  10.     //是否最小值、最大值、中間值  
  11.     this._IsMin = this._IsMax = this._IsMid = false;  
  12.     //實(shí)例化一個(gè)拖放對(duì)象,并限定范圍  
  13.     this._drag = new Drag(this.Bar, { Limit: true, mxContainer: this.Container,  
  14.         onStart: Bind(thisthis.DragStart), onStop: Bind(thisthis.DragStop), onMove: Bind(thisthis.Move)  
  15.     });  
  16.       
  17.     this.SetOptions(options);  
  18.       
  19.     this.WheelSpeed = Math.max(0, this.options.WheelSpeed);  
  20.     this.KeySpeed = Math.max(0, this.options.KeySpeed);  
  21.       
  22.     this.MinValue = this.options.MinValue;  
  23.     this.MaxValue = this.options.MaxValue;  
  24.       
  25.     this.RunTime = Math.max(1, this.options.RunTime);  
  26.     this.RunStep = Math.max(1, this.options.RunStep);  
  27.       
  28.     this.Ease = !!this.options.Ease;  
  29.     this.EaseStep = Math.max(1, this.options.EaseStep);  
  30.       
  31.     this.onMin = this.options.onMin;  
  32.     this.onMax = this.options.onMax;  
  33.     this.onMid = this.options.onMid;  
  34.       
  35.     this.onDragStart = this.options.onDragStart;  
  36.     this.onDragStop = this.options.onDragStop;  
  37.       
  38.     this.onMove = this.options.onMove;  
  39.       
  40.     this._horizontal = !!this.options.Horizontal;//一般不允許修改  
  41.       
  42.     //鎖定拖放方向  
  43.     this._drag[this._horizontal ? "LockY" : "LockX"] = true;  
  44.       
  45.     //點(diǎn)擊控制  
  46.     addEventHandler(this.Container, "click", BindAsEventListener(thisfunction(e){ this._ondrag || this.ClickCtrl(e);}));  
  47.     //取消冒泡,防止跟Container的click沖突  
  48.     addEventHandler(this.Bar, "click", BindAsEventListener(thisfunction(e){ e.stopPropagation(); }));  
  49.       
  50.     //設(shè)置鼠標(biāo)滾輪控制  
  51.     this.WheelBind(this.Container);  
  52.     //設(shè)置方向鍵控制  
  53.     this.KeyBind(this.Container);  
  54.     //修正獲取焦點(diǎn)  
  55.     var oFocus = isIE ? (this.KeyBind(this.Bar), this.Bar) : this.Container;  
  56.     addEventHandler(this.Bar, "mousedown"function(){ oFocus.focus(); });  
  57.     //ie鼠標(biāo)捕獲和ff的取消默認(rèn)動(dòng)作都不能獲得焦點(diǎn),所以要手動(dòng)獲取  
  58.     //如果ie把focus設(shè)置到Container,那么在出現(xiàn)滾動(dòng)條時(shí)ie的focus可能會(huì)導(dǎo)致自動(dòng)滾屏  
  59.   },  
  60.   //設(shè)置默認(rèn)屬性  
  61.   SetOptions: function(options) {  
  62.     this.options = {//默認(rèn)值  
  63.         MinValue:    0,//最小值  
  64.         MaxValue:    100,//最大值  
  65.         WheelSpeed: 5,//鼠標(biāo)滾輪速度,越大越快(0則取消鼠標(biāo)滾輪控制)  
  66.         KeySpeed:     50,//方向鍵滾動(dòng)速度,越大越慢(0則取消方向鍵控制)  
  67.         Horizontal:    true,//是否水平滑動(dòng)  
  68.         RunTime:    20,//自動(dòng)滑移的延時(shí)時(shí)間,越大越慢  
  69.         RunStep:    2,//自動(dòng)滑移每次滑動(dòng)的百分比  
  70.         Ease:        false,//是否緩動(dòng)  
  71.         EaseStep:    5,//緩動(dòng)等級(jí),越大越慢  
  72.         onMin:        function(){},//最小值時(shí)執(zhí)行  
  73.         onMax:        function(){},//最大值時(shí)執(zhí)行  
  74.         onMid:        function(){},//中間值時(shí)執(zhí)行  
  75.         onDragStart:function(){},//拖動(dòng)開(kāi)始時(shí)執(zhí)行  
  76.         onDragStop:    function(){},//拖動(dòng)結(jié)束時(shí)執(zhí)行  
  77.         onMove:        function(){}//滑動(dòng)時(shí)執(zhí)行  
  78.     };  
  79.     Extend(this.options, options || {});  
  80.   },  
  81.   //開(kāi)始拖放滑動(dòng)  
  82.   DragStart: function() {  
  83.       this.onDragStart();  
  84.     this._ondrag = true;  
  85.   },  
  86.   //結(jié)束拖放滑動(dòng)  
  87.   DragStop: function() {  
  88.       this.onDragStop();  
  89.     setTimeout(Bind(thisfunction(){ this._ondrag = false; }), 10);  
  90.   },  
  91.   //滑動(dòng)中  
  92.   Move: function() {  
  93.       this.onMove();  
  94.       
  95.     var percent = this.GetPercent();  
  96.     //最小值判斷  
  97.     if(percent > 0){  
  98.         this._IsMin = false;  
  99.     }else{  
  100.         if(!this._IsMin){ this.onMin(); this._IsMin = true; }  
  101.     }  
  102.     //最大值判斷  
  103.     if(percent < 1){  
  104.         this._IsMax = false;  
  105.     }else{  
  106.         if(!this._IsMax){ this.onMax(); this._IsMax = true; }  
  107.     }  
  108.     //中間值判斷  
  109.     if(percent > 0 && percent < 1){  
  110.         if(!this._IsMid){ this.onMid(); this._IsMid = true; }  
  111.     }else{  
  112.         this._IsMid = false;  
  113.     }  
  114.   },  
  115.   //鼠標(biāo)點(diǎn)擊控制  
  116.   ClickCtrl: function(e) {  
  117.     var o = this.Container, iLeft = o.offsetLeft, iTop = o.offsetTop;  
  118.     while (o.offsetParent) { o = o.offsetParent; iLeft += o.offsetLeft; iTop += o.offsetTop; }  
  119.     //考慮有滾動(dòng)條,要用pageX和pageY  
  120.     this.EasePos(e.pageX - iLeft - this.Bar.offsetWidth / 2, e.pageY - iTop - this.Bar.offsetHeight / 2);  
  121.   },  
  122.   //鼠標(biāo)滾輪控制  
  123.   WheelCtrl: function(e) {  
  124.     var i = this.WheelSpeed * e.detail;  
  125.     this.SetPos(this.Bar.offsetLeft + i, this.Bar.offsetTop + i);  
  126.     //防止觸發(fā)其他滾動(dòng)條  
  127.     e.preventDefault();  
  128.   },  
  129.   //綁定鼠標(biāo)滾輪  
  130.   WheelBind: function(o) {  
  131.       //鼠標(biāo)滾輪控制  
  132.     addEventHandler(o, isIE ? "mousewheel" : "DOMMouseScroll", BindAsEventListener(thisthis.WheelCtrl));  
  133.   },  
  134.   //方向鍵控制  
  135.   KeyCtrl: function(e) {  
  136.     if(this.KeySpeed){  
  137.         var iLeft = this.Bar.offsetLeft, iWidth = (this.Container.clientWidth - this.Bar.offsetWidth) / this.KeySpeed  
  138.             , iTop = this.Bar.offsetTop, iHeight = (this.Container.clientHeight - this.Bar.offsetHeight) / this.KeySpeed;  
  139.         //根據(jù)按鍵設(shè)置值  
  140.         switch (e.keyCode) {  
  141.             case 37 ://左  
  142.                 iLeft -= iWidth; break;  
  143.             case 38 ://上  
  144.                 iTop -= iHeight; break;  
  145.             case 39 ://右  
  146.                 iLeft += iWidth; break;  
  147.             case 40 ://下  
  148.                 iTop += iHeight; break;  
  149.             default :  
  150.                 return;//不是方向按鍵返回  
  151.         }  
  152.         this.SetPos(iLeft, iTop);  
  153.         //防止觸發(fā)其他滾動(dòng)條  
  154.         e.preventDefault();  
  155.     }  
  156.   },  
  157.   //綁定方向鍵  
  158.   KeyBind: function(o) {  
  159.     addEventHandler(o, "keydown", BindAsEventListener(thisthis.KeyCtrl));  
  160.     //設(shè)置tabIndex使設(shè)置對(duì)象能支持focus  
  161.     o.tabIndex = -1;  
  162.     //取消focus時(shí)出現(xiàn)的虛線(xiàn)框  
  163.     isIE || (o.style.outline = "none");  
  164.   },  
  165.   //獲取當(dāng)前值  
  166.   GetValue: function() {  
  167.     //根據(jù)最大最小值和滑動(dòng)百分比取值  
  168.     return this.MinValue + this.GetPercent() * (this.MaxValue - this.MinValue);  
  169.   },  
  170.   //設(shè)置值位置  
  171.   SetValue: function(value) {  
  172.     //根據(jù)最大最小值和參數(shù)值設(shè)置滑塊位置  
  173.     this.SetPercent((value- this.MinValue)/(this.MaxValue - this.MinValue));  
  174.   },  
  175.   //獲取百分比  
  176.   GetPercent: function() {  
  177.     //根據(jù)滑動(dòng)條滑塊取百分比  
  178.     return this._horizontal ? this.Bar.offsetLeft / (this.Container.clientWidth - this.Bar.offsetWidth)  
  179.         : this.Bar.offsetTop / (this.Container.clientHeight - this.Bar.offsetHeight)  
  180.   },  
  181.   //設(shè)置百分比位置  
  182.   SetPercent: function(value) {  
  183.     //根據(jù)百分比設(shè)置滑塊位置  
  184.     this.EasePos((this.Container.clientWidth - this.Bar.offsetWidth) * value, (this.Container.clientHeight - this.Bar.offsetHeight) * value);  
  185.   },  
  186.   //自動(dòng)滑移(是否遞增)  
  187.   Run: function(bIncrease) {  
  188.     this.Stop();  
  189.     //修正一下bIncrease  
  190.     bIncrease = !!bIncrease;  
  191.     //根據(jù)是否遞增來(lái)設(shè)置值  
  192.     var percent = this.GetPercent() + (bIncrease ? 1 : -1) * this.RunStep / 100;  
  193.     this.SetPos((this.Container.clientWidth - this.Bar.offsetWidth) * percent, (this.Container.clientHeight - this.Bar.offsetHeight) * percent);  
  194.     //如果沒(méi)有到極限值就繼續(xù)滑移  
  195.     if(!(bIncrease ? this._IsMax : this._IsMin)){  
  196.         this._timer = setTimeout(Bind(thisthis.Run, bIncrease), this.RunTime);  
  197.     }  
  198.   },  
  199.   //停止滑移  
  200.   Stop: function() {  
  201.     clearTimeout(this._timer);  
  202.   },  
  203.   //緩動(dòng)滑移  
  204.   EasePos: function(iLeftT, iTopT) {  
  205.     this.Stop();  
  206.     //必須是整數(shù),否則可能死循環(huán)  
  207.     iLeftT = Math.round(iLeftT); iTopT = Math.round(iTopT);  
  208.     //如果沒(méi)有設(shè)置緩動(dòng)  
  209.     if(!this.Ease){ this.SetPos(iLeftT, iTopT); return; }  
  210.     //獲取緩動(dòng)參數(shù)  
  211.     var iLeftN = this.Bar.offsetLeft, iLeftS = this.GetStep(iLeftT, iLeftN)  
  212.     , iTopN = this.Bar.offsetTop, iTopS = this.GetStep(iTopT, iTopN);  
  213.     //如果參數(shù)有值  
  214.     if(this._horizontal ? iLeftS : iTopS){  
  215.         //設(shè)置位置  
  216.         this.SetPos(iLeftN + iLeftS, iTopN + iTopS);  
  217.         //如果沒(méi)有到極限值則繼續(xù)緩動(dòng)  
  218.         if(this._IsMid){ this._timer = setTimeout(Bind(thisthis.EasePos, iLeftT, iTopT), this.RunTime); }  
  219.     }  
  220.   },  
  221.   //獲取步長(zhǎng)  
  222.   GetStep: function(iTarget, iNow) {  
  223.     var iStep = (iTarget - iNow) / this.EaseStep;  
  224.     if (iStep == 0) return 0;  
  225.     if (Math.abs(iStep) < 1) return (iStep > 0 ? 1 : -1);  
  226.     return iStep;  
  227.   },  
  228.   //設(shè)置滑塊位置  
  229.   SetPos: function(iLeft, iTop) {  
  230.     this.Stop();  
  231.     this._drag.SetPos(iLeft, iTop);  
  232.   }  
  233. };  

下載完整測(cè)試代碼

原文鏈接:http://www.cnblogs.com/cloudgamer/

責(zé)任編輯:張偉 來(lái)源: cloudgamer的博客
相關(guān)推薦

2024-09-18 09:18:11

2024-05-30 08:23:37

ViewPager滑動(dòng)效果接口

2024-07-25 08:55:47

進(jìn)度條水缸進(jìn)度動(dòng)畫(huà)效果

2023-11-22 07:47:34

2009-08-17 17:15:48

C# 進(jìn)度條效果

2012-01-17 13:58:17

JavaSwing

2015-01-22 16:04:06

iPhone

2009-12-28 15:39:33

WPF滑動(dòng)條

2011-09-01 13:17:46

JQuery滾動(dòng)

2017-04-27 21:00:33

Android滑動(dòng)分析

2017-03-22 10:35:06

AndroidRecyclerVie滑動(dòng)效果

2023-07-18 15:49:22

HTMLCSS

2011-07-08 10:15:15

IPhone 動(dòng)畫(huà)

2017-02-06 13:00:49

Android翻轉(zhuǎn)卡片動(dòng)畫(huà)效果

2024-01-25 10:37:33

MySQL數(shù)據(jù)庫(kù)ES

2015-07-30 09:35:24

滑動(dòng)返回代碼

2011-05-04 09:05:39

Flash

2015-07-23 15:15:06

動(dòng)態(tài)彈出

2022-03-11 07:22:20

CSS陰影基礎(chǔ)前端

2021-01-19 12:16:10

CSS前端UI
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)