不間斷滾動圖片Javascript特效講解
我們來分析下代碼(代碼中我已經寫了很詳細的注釋),要之其所以然,在解讀別人的代碼中學習提高自己,然后可以靈活運用,這個才是我將這個效果貼出來的主要目的,代碼如下:
scrollver.js
- scrollVertical.prototype.scrollArea=null; // 滾動的區域
- scrollVertical.prototype.scrollMsg=null; // 要滾動的內容
- scrollVertical.prototype.unitHeight=0; // 單獨一行滾動內容的高度(程序中通過過的要滾動行的一個節點的offsetHeight獲得)
- scrollVertical.prototype.msgHeight=0; // 整個滾動內容的高度
- scrollVertical.prototype.copyMsg=null; // 復制滾動內容(程序中使用復制scrollMsg.innerHTML來獲得的)
- scrollVertical.prototype.scrollValue=0; // 滾動的值
- scrollVertical.prototype.scrollHeight=0; // 滾動高度
- scrollVertical.prototype.isStop=true; // 停止滾動
- scrollVertical.prototype.isPause=false; // 暫停滾動
- scrollVertical.prototype.scrollTimer=null; // 滾動計時器
- scrollVertical.prototype.speed=2000; // (默認)滾動的時間間隔2秒
- /**
- * @method isMoz - 判斷是否為Mozilla系列瀏覽器
- */
- scrollVertical.prototype.isMoz = function(){
- return navigator.userAgent.toLowerCase().indexOf('gecko') > 0;
- };
- /**
- * @method play - 滾動信息的處理方法(函數)
- * @param {Object} o - 滾動類
- */
- scrollVertical.prototype.play = function(o){
- var s_msg = o.scrollMsg;
- var c_msg = o.copyMsg;
- var s_area = o.scrollArea;
- var msg_h = o.msgHeight;
- var anim = function(){
- // 如果已經開始計時(間隔時間執行向上滾動),
- // 就停止它(以免無限制執行,耗系統資源)。
- if (o.scrollTimer) {
- clearTimeout(o.scrollTimer);
- }
- // 如果暫停了滾動(鼠標放到了滾動層上)
- // 開始以10毫秒的時間間隔運行滾動
- if (o.isPause) {
- o.scrollTimer = setTimeout(anim, 10);
- return;
- }
- // 當顯示完所有信息后(這時滾動的距離就等于要滾動信息的高度msg_h)
- // 這時又重新開始滾動,將滾動距離清零
- if (msg_h - o.scrollValue <= 0) {
- o.scrollValue = 0;
- }
- else {
- o.scrollValue += 1;
- o.scrollHeight += 1;
- }
- // 根據瀏覽器的不同,處理滾動
- if (o.isMoz) { // Mozilla引擎瀏覽器
- s_area.scrollTop = o.scrollValue;
- }
- else { // 其余的瀏覽器則使用控制CSS樣式處理滾動
- s_msg.style.top = -1 * o.scrollValue + "px";
- c_msg.style.top = (msg_h - o.scrollValue) + "px";
- }
- // 滾動高度等于顯示滾動區域高度時(滾動完一行,一行內容全部顯示)
- // 暫停4秒中,然后再開始執行下依次滾動。
- if (o.scrollHeight % s_area.offsetHeight == 0) {
- o.scrollTimer = setTimeout(anim, o.speed);
- }
- else {
- // 在兩行內容之間過度滾動時,每10豪秒上升1px
- o.scrollTimer = setTimeout(anim, 10);
- }
- };
- // 執行滾動
- anim();
- };
- /**
- * scrollVertical 垂直滾動的構造函數
- * @param {Object} disp - 必須 顯示滾動區域的DOM節點(或節點ID)
- * @param {Object} msg - 必須 被顯示的信息的DOM節點(或節點ID)
- * @param {string} tg - 可選 以什么標記為一行的標簽名稱(tagName)
- */
- function scrollVertical(disp, msg, tg){
- // 給在之前定義的this.scrollArea付值
- if (typeof(disp) == 'string') {
- // 如果disp給的是節點的ID,通過document.getElementById獲取該節點
- // 然后付值給this.scrollArea
- this.scrollArea = document.getElementById(disp);
- }
- else {
- // 如果是DOM節點,直接付給this.scrollArea
- this.scrollArea = disp;
- }
- // 以給this.scrollArea相同的方法給this.scrollMsg付值
- if (typeof(msg) == 'string') {
- this.scrollMsg = document.getElementById(msg);
- }
- else {
- this.scrollMsg = msg;
- }
- // 為了開發方便,
- // 不用一直寫this.scrollMsg這么常的名字,
- // 將兩個對象付給局部變量
- var s_msg = this.scrollMsg;
- var s_area = this.scrollArea;
- // 如果沒有給定一行的識別標簽,
- // 默認將li標簽認為是一行的標簽
- // 所以上面介紹的,tag參數是可選的
- if (!tg) {
- var tg = 'li';
- }
- // 獲取單行的高度
- // 獲取到***(s_msg.getElementsByTagName(tg)[0])tg(一行的標簽)的高度,作為單行的高度
- this.unitHeight = s_msg.getElementsByTagName(tg)[0].offsetHeight;
- // 獲取整個信息框的高度
- // 公式為 單行高度(unitHeight)*行數(s_msg.getElementsByTagName(tg).length,顯示信息中包含多少個tg(行)標簽)
- this.msgHeight = this.unitHeight * s_msg.getElementsByTagName(tg).length;
- /*
- * 復制要顯示的信息:
- * 連續滾動的實現其實就是通過復制信息,
- * 并將復制的信添加到原始信息后
- * 當原始信息滾動顯示完成,就接著滾動顯示復制的信息
- * 但給人的錯覺是,我們看到信息連續不斷的顯示
- */
- // 創建復制內容節點
- var copydiv = document.createElement('div');
- // 這個地方感覺有點嵌妥
- // 直接使用element.id的方式,不過看上去,主流的瀏覽器都支持
- // 標準的DOM Core方法:
- // copydiv.setAttribute('id',s_area.id + "_copymsgid")
- copydiv.id = s_area.id + "_copymsgid";
- // 復制原始的信息
- // 將原始的信息s_msg中的內容,直接用innerHTML寫到
- copydiv.innerHTML = s_msg.innerHTML;
- // 設置復制信息節點的高度
- copydiv.style.height = this.msgHeight + "px";
- // 將復制節點添加到原始接點(scrollMsg)后
- // 其實實現的方法就是將復制信息節點(copydiv)添家到顯示區域的節點(scrollArea)中
- s_area.appendChild(copydiv);
- this.copyMsg = copydiv;
- // 開始執行滾動方法
- this.play(this);
- }
我在腳本的注釋中已經說了這個效果的實現原理,而實現一個效果的關鍵就是在于運用setTimeout方法和clearTimeout方法。
setTimeout(func,time)
setTimeout是window對象的一個方法,所以如果要是看到這么寫window.setTimeout你不要感到奇怪,我們平時一般都省略了window。
setTimeout方法接受兩個參數:
func - 在指定時間間隔內要執行的函數;
time - 執行函數的時間間隔(以毫秒為單位,1000毫秒等于1秒)
我一開始沒有解釋setTimeout的功能,而是先說了兩個參數的意思,我想大家看了后就會有所了解,setTimeout的功能就是:設置定時器,在一段時間之后執行指定的代碼。
不如本例中的:
setTimeout(anim, o.speed);
也許你有看過類似的寫法:
- function dosomething(){
- // do something
- }
- setTimeOout('dosomething',1000);
個人建議不要這么寫,是這樣的代碼的可讀性太差,雖然也可以正常執行。相信你看到的類似的代碼也是很久前的東西了。如果你還在新買的某本書中看到這樣的寫法,我想你可能很不幸買了本爛書。現在一般我們都這么做:
- function whatWeDoNow(){
- var str = 'this is what we do now';
- if(doalert) {
- clearTimeout(doalert)
- }
- var doalert = setTimeout(function(){
- alert(str);
- },1000);
- }
而且不知道你發現沒有,這么寫還有一個好處,你的function還可以接受其他的參數,比如這里我們可以接受whatWeDoNow()函數中的局部變量。如果你再結合閉包的使用,好處會更顯而易見。
剛才說的一點應該說是一個不好的使用setTimeout的習慣。呵呵,接下來我還要說的一個更不好的使用習慣就是只使用setTimeout()方法,而不使用clearTimeout()方法。
clearTimeout(itimeoutid)
clearTimeout()方法的功能是停止定時器,大家看上面的代碼:
clearTimeout(o.scrollTimer);
Timer(定時器),夠直接吧。那么為什么要停止定時器?什么時候停止呢?
為什么要停,我想用個反問:能一直不停嗎,你的機器受得了嗎?這里我想應該說說我們使用setTimeout的目的,我們通常使用它來實現像本例這 樣的動畫效果。需要在很短的時間內連續不斷的執行定時器,當然它是要占資源的啊。想想,只是不斷的創建,而且往往我們做的處理,在1秒中內會執行很多次函 數,一兩次還好,上百上千次,而且一個復雜些的動畫,執行很短的時間內幾萬次也不是沒有可能事情。你想想,如果我們不在每執行完一次后,銷毀它。要是再加 上定時器執行的函數又是個比較NB點的運算,你的寶貴的系統資源...,呵呵!
所以應該向我給的例子中那樣,記得在每次執行了定時器后停止(銷毀,釋放資源)它。
- function whatWeDoNow(){
- var str = 'this is what we do now';
- if(doalert) {
- clearTimeout(doalert); // clear
- }
- var doalert = setTimeout(function(){
- alert(str);
- },1000);
- }
- if (o.scrollTimer) {
- clearTimeout(o.scrollTimer); // clear
- }
呵呵,其實銷毀的方法很簡單,就是在每次創建定時器前,判斷是否已經創建了訂時器,就像特效例子中的
- if (o.scrollTimer) {
- clearTimeout(o.scrollTimer); // clear
- }
- ....
- ....
- if (o.scrollHeight % s_area.offsetHeight == 0) {
- o.scrollTimer = setTimeout(anim, o.speed);
- }
- else {
- o.scrollTimer = setTimeout(anim, 10);
- }
是不是一個很流暢的循環?現在大家應該知道了,為什么要clearTimeout和何時clearTimeout了嗎?
【編輯推薦】