楊慶虎
(貴州城市職業(yè)學(xué)院,貴州 貴陽(yáng) 550025)
Web 程序設(shè)計(jì)、移動(dòng)應(yīng)用開(kāi)發(fā),都需要良好的UI界面和有趣的交互。運(yùn)動(dòng)不僅能有效地突出重點(diǎn)、吸引客戶的眼球,還能增加系統(tǒng)的趣味性,實(shí)現(xiàn)靜止對(duì)象無(wú)法實(shí)現(xiàn)的功能。如何讓圖片、對(duì)話框、導(dǎo)航條、留言面板等網(wǎng)頁(yè)元素根據(jù)需要實(shí)現(xiàn)特定的運(yùn)動(dòng)特效成為系統(tǒng)UI設(shè)計(jì)師關(guān)注和研究的重點(diǎn)。解決JavaScript對(duì)象運(yùn)動(dòng)問(wèn)題最簡(jiǎn)單和有效的方法就是采用運(yùn)動(dòng)框架??蚣艿母拍钭钤缙鹪从赟malltalk 環(huán)境,其中最著名的框架是Smalltalk-80 的用戶界面框架MVC(Model-View-Controller),即將對(duì)象、屬性、目標(biāo)等參數(shù)封裝到一個(gè)函數(shù)中,使用時(shí)調(diào)用函數(shù)即可,被封裝好的函數(shù)即稱為框架。
基礎(chǔ)運(yùn)動(dòng)是高級(jí)運(yùn)動(dòng)研究的基礎(chǔ),所有JavaScript運(yùn)動(dòng)都包括運(yùn)動(dòng)驅(qū)動(dòng)事件、運(yùn)動(dòng)方式、運(yùn)動(dòng)速度等。運(yùn)動(dòng)驅(qū)動(dòng)事件是驅(qū)使運(yùn)動(dòng)的觸發(fā)事件,如頁(yè)面裝載、鼠標(biāo)移入移出、鼠標(biāo)點(diǎn)擊等。運(yùn)動(dòng)方式主要是對(duì)象運(yùn)動(dòng)前后屬性的變化,如實(shí)現(xiàn)位置改變的左右移動(dòng)、上下移動(dòng),實(shí)現(xiàn)特定屬性如透明度變化等。運(yùn)動(dòng)速度主要由定時(shí)器和預(yù)設(shè)速度決定。
構(gòu)建運(yùn)動(dòng)框架要注意兩點(diǎn):首先,在開(kāi)啟運(yùn)動(dòng)前要關(guān)閉已有定時(shí)器;其次,在運(yùn)動(dòng)框架中要將運(yùn)動(dòng)和停止使用if…else…語(yǔ)句隔離開(kāi),不能攪和在一起,否則會(huì)出現(xiàn)預(yù)想不到的Bug。下面以常見(jiàn)的側(cè)邊欄分享為例進(jìn)行說(shuō)明。側(cè)邊欄由div1 和span 標(biāo)簽組成,側(cè)邊欄分享JS代碼如下:
上述代碼定時(shí)器關(guān)閉條件為Math.abc(oDiv.offsetLeft-iTarget) 在實(shí)際項(xiàng)目開(kāi)發(fā)中,勻速運(yùn)動(dòng)的情況比較少見(jiàn),更多的是緩沖運(yùn)動(dòng),如JavaScript 中的手風(fēng)琴效果等。緩沖運(yùn)動(dòng)實(shí)現(xiàn)的原理是運(yùn)動(dòng)對(duì)象離目標(biāo)值越大運(yùn)動(dòng)速度越快,反之則越慢,速度的快慢由距離的遠(yuǎn)近決定,用iSpeed 表示對(duì)象速度,iTarget 表示目標(biāo)值,offsetValue表示當(dāng)前值,m表示速度系數(shù),則緩沖運(yùn)動(dòng)的速度公式可表示為:iSpeed=(iTarget-offsetValue)/m。 例如需要移動(dòng)的對(duì)象為div1,設(shè)計(jì)div1 的初始水平位置為0,通過(guò)分析知,div1 緩沖運(yùn)動(dòng)的速度在不斷減小,當(dāng)值減小至計(jì)算機(jī)內(nèi)存無(wú)法精確表示時(shí),此時(shí)一直以這個(gè)速度循環(huán)運(yùn)行,但對(duì)象無(wú)法移動(dòng),且對(duì)象位置停留在較近的某一點(diǎn)但沒(méi)有到達(dá)目標(biāo)點(diǎn)。經(jīng)分析知引發(fā)此問(wèn)題的原因是“ iSpeed=(iTarget-oDiv.offsetLeft)/m;”。因此,需要對(duì)程序進(jìn)行改進(jìn),為了保證對(duì)象向左移動(dòng)或向右移動(dòng)均有效,引入JavaScript中的取整函數(shù),當(dāng)速度大于零向左移動(dòng)時(shí)向上取整,即使用cell函數(shù),當(dāng)速度小于零向右移動(dòng)時(shí)向下取整,即使用floor 函數(shù),因此在速度語(yǔ)句下面增加速度取整語(yǔ)句:iSpeed=iSpeed>0?Math.ceil(iSpeed):Math.floor(iSpeed);同時(shí),由于取整的實(shí)現(xiàn),對(duì)象運(yùn)動(dòng)速度最后必為1,隨著時(shí)間的推移,運(yùn)動(dòng)物體必將到達(dá)目標(biāo)點(diǎn),因此可將oDiv.offsetLeft>=iTarget 中的判定條件修改為“==”即可。經(jīng)實(shí)驗(yàn)運(yùn)動(dòng)對(duì)象能實(shí)現(xiàn)緩沖效果并到達(dá)目標(biāo)點(diǎn)。 如圖1 所示,設(shè)可視窗口頂部隱藏區(qū)域的高度為scrollTop,窗口可視區(qū)域高度為clientHight,側(cè)邊欄高度為offsetHeight,當(dāng)div 對(duì)象垂直居中時(shí)不難算出側(cè)邊欄的頂部距離Top,其計(jì)算公式為,Top=scroppTop+(clientHeight-offsetHeight)/2。采用水平緩沖運(yùn)動(dòng)原理,可以實(shí)現(xiàn)對(duì)象div的垂直居中效果。 圖1 側(cè)邊樣垂直居中示意圖 瀏覽器兼容問(wèn)題一直是JavaScript設(shè)計(jì)的難題,窗口隱藏區(qū)域高度取值(scrollTop),就存在瀏覽器兼容Bug,此處通過(guò)或運(yùn)算給予解決,解決的代碼為“scrollTop=document.documentElement.scrollTop||document.body.scrollTop;”。另外,通過(guò)測(cè)試,發(fā)現(xiàn)div1 對(duì)象到達(dá)目標(biāo)后有輕微的抖動(dòng),經(jīng)檢查發(fā)現(xiàn)t 值為小數(shù)造成,因此,對(duì)目標(biāo)值t采用parseInt(t)取整即可解決Bug。 多物體運(yùn)動(dòng)要解決搶占定時(shí)器問(wèn)題,必須為每個(gè)運(yùn)動(dòng)對(duì)象定義獨(dú)立定時(shí)器,同時(shí),不僅要弄清楚運(yùn)動(dòng)目標(biāo)點(diǎn)是哪里,還要弄清楚運(yùn)動(dòng)的對(duì)象是什么。例如,下列代碼實(shí)現(xiàn)了一組div 寬度隨著鼠標(biāo)移入變寬,移出變窄的運(yùn)動(dòng)效果。 在多物體運(yùn)動(dòng)中,運(yùn)動(dòng)對(duì)象是多個(gè),因此不能再使用document.getElementById()方法來(lái)獲取對(duì)象,而是要通過(guò)諸如getElementsByTagName()、document.getElementsByClassName()等方式獲取。上述代碼中“oDiv[i].timer=null;”為每個(gè)div 設(shè)置獨(dú)立的定時(shí)器,避免了搶占定時(shí)器問(wèn)題,在對(duì)象傳參過(guò)程中不僅傳遞了目標(biāo)值iTarget,而且還明確了運(yùn)動(dòng)對(duì)象obj。 在多物體運(yùn)動(dòng)中所有的屬性和變量必須獨(dú)占,不能共用。例如,對(duì)多個(gè)div 進(jìn)行透明度的運(yùn)動(dòng),此時(shí),必須為每個(gè)對(duì)象單獨(dú)定義透明度存儲(chǔ)對(duì)象,如果共享則可能會(huì)出現(xiàn)對(duì)象A 要讓透明度增大,對(duì)象B 卻要讓透明度減小的矛盾。 在任意值運(yùn)動(dòng)框架中首先要解決offset(offsetWidth、offsetHeight)Bug 問(wèn)題,offset 值不僅包括樣式中對(duì)象的長(zhǎng)(Width)、寬(Height)值,還包括了邊框等值。 如上述代碼隨著時(shí)間的推移div 對(duì)象的寬度不斷變窄,但如果給div 中的樣式加上邊框后,實(shí)際的運(yùn)行效果則會(huì)隨著時(shí)間的推移不斷變寬,這與程序的初衷相悖。為什么會(huì)出現(xiàn)這種相悖現(xiàn)象?設(shè)對(duì)象的初始寬度(style.width)為100,加了1 像素的邊框后,由于offset 值包括邊框的寬度,因此offsetWidth 值為102,減去1 后對(duì)象寬度變?yōu)?01,如此循環(huán),不難看出對(duì)象的寬度會(huì)逐漸增大。 解決上述問(wèn)題最有效的方式即獲取對(duì)象的實(shí)際寬、高(width、Height)值,可封裝一個(gè)函數(shù),代碼如下: 然后將對(duì)象寬度修改語(yǔ)句“oDiv.style.width=oDiv.offsetWidth-1+'px';”變更為oDiv.style.width=parseInt(getStyle(oDiv,'width'))-1+'px';即可。 任意對(duì)象任意值的運(yùn)動(dòng)框架代碼如下: 可將上述代碼封裝到j(luò)s文件中(如MoveFrame.js)供其他運(yùn)動(dòng)場(chǎng)景使用。 使用封裝好的startMove(obj,attr,iTarget)運(yùn)動(dòng)框架解決系統(tǒng)開(kāi)發(fā)中的flash運(yùn)動(dòng)效果如圖2所示。 圖2 運(yùn)動(dòng)框架效果圖 ⑴鼠標(biāo)移入瀏覽窗口左或右邊,以淡入淡出顯示左或右導(dǎo)航箭頭,并且可以點(diǎn)擊箭頭實(shí)現(xiàn)圖片換頁(yè)。 ⑵大圖換頁(yè)方式為從上向下拉,對(duì)應(yīng)縮略圖透明度增加至100%,且位于縮略圖中間。 ⑶點(diǎn)擊縮略圖,縮略圖透明度增加至100%,且游覽窗口顯示對(duì)應(yīng)大圖。 ⑴采用CSS樣式為頁(yè)面布局,布局效果如圖1。 ⑵引入封裝好的運(yùn)動(dòng)框架js文件。 ⑶代碼實(shí)現(xiàn)。 在代碼實(shí)現(xiàn)中可以通過(guò)語(yǔ)句“aEle=document.getElementsByTagName('*');”選出樣式中的所有元素。語(yǔ)句“if(this.index==iNow)return;”避免重復(fù)點(diǎn)擊激發(fā)運(yùn)動(dòng)效果。由于主窗口圖層堆疊在一起,前面的圖層擋住了后面的圖層,因此,必須借助語(yǔ)句“aBigLi[iNow].style.zIndex=iMinZindex++;”將當(dāng)前圖層移至頂層,這樣才能使用戶看到圖片向下拉伸的運(yùn)動(dòng)效果。設(shè)有m 張縮略圖,點(diǎn)擊首張和最后一張縮略圖時(shí),其位置不變,即為0 和-(m-2)*li.width,點(diǎn)擊其余圖片時(shí)移動(dòng)至中間,因此,其位置變化為-(m-1)*li.width,即使用if(iNow==0){…}else if(iNow==aSmallLi.length-1){…}else{…}語(yǔ)句控制。tab()函數(shù)實(shí)現(xiàn)了縮略圖與大圖運(yùn)動(dòng)的關(guān)聯(lián),后續(xù)程序中多次用到,因此進(jìn)行了封裝。 上述程序應(yīng)用運(yùn)動(dòng)框架封裝實(shí)現(xiàn)了瀏覽窗口導(dǎo)航箭頭換頁(yè),大圖、小圖運(yùn)動(dòng)效果等,程序簡(jiǎn)潔,易讀性好,代碼利用率高。運(yùn)動(dòng)框架功能強(qiáng)大,不僅可以較好的完成上述運(yùn)動(dòng)效果,還可以用該框架完成諸如自動(dòng)播放、增加圖片說(shuō)明等運(yùn)動(dòng)事件處理。 運(yùn)動(dòng)框架是構(gòu)建系統(tǒng)運(yùn)動(dòng)的主要方式之一,應(yīng)用好運(yùn)動(dòng)框架不僅能高效地實(shí)現(xiàn)運(yùn)動(dòng)效果,使程序簡(jiǎn)潔、易讀、提高代碼復(fù)用率,而且還能減少程序維護(hù)工作量,提高系統(tǒng)維護(hù)效率。本文從前端運(yùn)動(dòng)設(shè)計(jì)驅(qū)動(dòng)事件、運(yùn)動(dòng)方式、運(yùn)動(dòng)速度等基礎(chǔ)進(jìn)行分析,對(duì)單物體勻速運(yùn)動(dòng)、水平緩沖運(yùn)動(dòng)、側(cè)邊欄緩沖居中的特點(diǎn)進(jìn)行研究,并基于單物體運(yùn)動(dòng)的基礎(chǔ)構(gòu)建了多物體任意值運(yùn)動(dòng)框架,解決了系統(tǒng)中任意對(duì)象、任意屬性、任意值的運(yùn)動(dòng)設(shè)計(jì)。設(shè)計(jì)的案例可以應(yīng)用于系統(tǒng)開(kāi)發(fā)中,也可以做為教學(xué)實(shí)踐案例。在系統(tǒng)的實(shí)際應(yīng)用中可以基于JSON數(shù)據(jù)對(duì)框架改進(jìn)和應(yīng)用,實(shí)現(xiàn)完美運(yùn)動(dòng)框架。2.2 水平緩沖運(yùn)動(dòng)
2.3 側(cè)邊欄緩沖居中
3 多物體運(yùn)動(dòng)框架
3.1 多物體單屬性運(yùn)動(dòng)框架
3.2 多物體任意值運(yùn)動(dòng)框架
4 運(yùn)動(dòng)框架使用案例
4.1 使用案例場(chǎng)景說(shuō)明
4.2 實(shí)現(xiàn)說(shuō)明
5 總結(jié)