国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > JS > 正文

手把手教你用JS創(chuàng)建幻燈片特效

2024-09-06 12:40:52
字體:
供稿:網(wǎng)友

javascript創(chuàng)建可維護幻燈片效果。


幻燈片效果

顯然,效果很實用。對于這個效果,我們并不解釋如何去使用效果庫,而是講解如何創(chuàng)建類似的效果,并保持他的可用性,分離式(unobtrusive),可維護性(讓未來的維護者,在不需要修改你的腳本的情況下,修改圖片,外觀或文本標(biāo)簽)。

無 javascript 狀態(tài)下,用戶將看到下面的效果:

添加和移除圖片、改變圖片的順序以及添加標(biāo)題,這些在 html 中都很容易做到。并且最后的解決并不意味著維護者需要懂任何 javascript 或者在源碼中搜索在哪里修改 css 的 class, id 或者文本標(biāo)簽。

你有沒有準(zhǔn)備好花費一些時間去一步一步的嘗試創(chuàng)建這個效果?

第一步:分析問題(analizing the problem)

創(chuàng)建一個好的腳本,第一步應(yīng)該是去分析哪些是你要完成的:我們想要創(chuàng)建一個照片的幻燈片效果,并且我們想要保持維護的方便。

如何創(chuàng)建一個幻燈片效果

在一個網(wǎng)站上擁有幻燈片有幾種方法:

  1. 在文檔中包含所有的圖片。
    當(dāng)他運行在無 javascript 狀態(tài),這是一個安全的選擇。而且,當(dāng)頁面被載完,所有的圖片也會將被載完。然而,這個方式只適用于少量的圖片。
  2. 在文檔中包含第一張圖片,并且有一個創(chuàng)建幻燈片功能的服務(wù)器端腳本。
    這也是相當(dāng)安全的,但是對于終端用戶來說,這是非常令人厭煩的——因為我不想加載整個頁面,僅想得到下一張照片。但對頁面展示和廣告點擊比較有效,這也是為什么大量的新聞?wù)军c使用這個方法。
  3. 在文檔中包含第一張圖片,并按需加載其他圖片。
    這個方法令你厭煩的是,必須依賴于 javascript ,并且要有一個維護照片列表的 javascript 數(shù)組。你還需提供一個加載指示器,用來顯示用戶一些正在發(fā)生的事情。

在我們的案例中,我們采取下面的圖片列表,用向前和向后的按鈕把他變成一個幻燈片效果,并且一個指示器告訴我們,照片總數(shù)中的哪張照片是當(dāng)前顯示的。

<ul id="slideshow">
    <li><img src="img/flat1.jpg" alt="hallway" /></li>
    <li><img src="img/flat2.jpg" alt="hob" /></li>
    <li><img src="img/flat3.jpg" alt="bathroom" /></li>
    <li><img src="img/flat4.jpg" alt="living room" /></li>
    <li><img src="img/flat5.jpg" alt="bedroom" /></li>
</ul>

最后的輸出會看起來像例子中的幻燈片效果。

依賴關(guān)系檢查

我們這里有一些元素依賴于 javascript 生成:文字指示器和向前和向下的鏈接。為了保持我們解決方法的可用性,我們需要確保一些事情:

  1. 僅當(dāng) javascript 可用(用戶信賴我們提供給他們使用的功能)時,這些元素應(yīng)該出現(xiàn)。一個鏈接,不能做任何違反用戶對我們的信任的事情。
  2. 不論輸入設(shè)備(讓我們不要依賴用戶是否有鼠標(biāo)),交互式元素都應(yīng)該可用。
  3. 圖片不應(yīng)該被隱藏,除非使用者能再次訪問他們。在技術(shù)上,僅顯示第一張圖片,且沒有向前和向后的鏈接是預(yù)留退路的做法,但是為什么要用戶已下載所有的圖片僅只看到第一張?

|||

第二步:規(guī)劃腳本(planning the script)

一旦你已經(jīng)評估了問題,并挑選出你想使用的解決方法,你便可以開始規(guī)劃腳本。本質(zhì)上,我們的腳本應(yīng)該做這些:

  • 檢查幻燈片列表是否存在,并且包含一些圖片(有理由為一張圖片創(chuàng)建一個幻燈片效果嗎?)。
  • 隱藏所有的照片,但不是第一個。
  • 創(chuàng)建向前和向后的鏈接,和一個顯示我們在哪的指示器。
  • 添加事件處理程序,使鏈接增加或減少當(dāng)前顯示的圖片編號。
  • 確保幻燈片效果沒有超出范圍,當(dāng)圖片編號小于 0 ,他應(yīng)該變?yōu)樽詈笠粡垐D片,反過來類似。

不同的功能處理

我們有一些方法處理這個問題。其中之一是使用 dom 遍歷每個 li 條目并隱藏他。在這個事件監(jiān)聽函數(shù),我們先隱藏先前顯示的 li (如果有的話),并顯示當(dāng)前的這個。

:顯示和隱藏代替圖片的 li 更有意義,因為他允許維護者在每個幻燈片上添加其他的元素,比如,一些標(biāo)題。

這個方法的問題在于,我們在 javascript 中做必要的樣式改變,這意味著如果有需要比剛才我們腳本中改變 display 從 block 到 none 更復(fù)雜的樣式改變,將使腳本變得更雜亂(沒有從行為中分離表現(xiàn))。

樣式留給 css 解析器

更簡潔的方法是將所有的外觀改變(在所有列表項下載完之后隱藏某些)都留給瀏覽器的 css 解析器。在我們的例子中,我們可以在幻燈片中使用一個 css 規(guī)則很容易地隱藏所有的列表項,并用一個特定的 class 重寫當(dāng)前條目的樣式。

html:

<ul id="slideshow">
    <li><img src="img/flat1.jpg" alt="hallway" /></li>
    <li><img src="img/flat2.jpg" alt="hob" /></li>
    <li><img src="img/flat3.jpg" alt="bathroom" /></li>
    <li><img src="img/flat4.jpg" alt="living room" /></li>
    <li><img src="img/flat5.jpg" alt="bedroom" /></li>
</ul>

css:

#slideshow li{
    display:none;
}
#slideshow li.current{
    display:block;
}

唯一的問題是,如果我們使 css 和 javascript 不可用,訪客將永遠不能訪問到其他圖片。因此,我們需要僅當(dāng) javascript 可用時,應(yīng)用這些樣式。技巧是,當(dāng) javascript 可用,在幻燈片的 ul 上應(yīng)用 class ,例如名為 js 。這允許我們僅當(dāng) javascript 可用時,顯示效果,通過在 css 中簡單的修改:

css:

#slideshow.js li{
    display:none;
}
#slideshow.js li.current{
    display:block;
}

這個 class 的鉤子(hook)也能被用來對幻燈片的靜態(tài)和動態(tài)版本提供一個完全不同的外觀。

我們所有的腳本需要做的是,通過移除或添加 current 的 class 來顯示和隱藏當(dāng)前及以前的照片。

為了確保我們的腳本將不會影響同一頁面上的其他腳本,我們將創(chuàng)建一個主要的對象,并在其上構(gòu)造所有的方法和屬性。這可以確保我們的 init() 函數(shù)將不會被覆蓋或覆蓋其他任何相同名字的函數(shù)。

javascript::

slideshow = {
    current:0, // 當(dāng)前幻燈片編碼
    init:function(){
        // 初始化和設(shè)置事件處理函數(shù)
    },
    show:function(e){
        // 事件監(jiān)聽器
    }
}

|||

第三步、基本的工具方法( essential tools)

現(xiàn)在,我們有了規(guī)劃和建立我們腳本的框架。是時候思考我們需要完成這個功能的一些工具方法。在其最低要求的情況下,dom 腳本的幫助庫應(yīng)該包括:

  • 一個注冊事件處理函數(shù)的方法,我們目前將使用 john resig 的 addevent() 方法。
  • 添加和移除 css 樣式名的方法。
  • 一個覆蓋 html 元素默認行為的方法。我們不希望出現(xiàn)鏈接的目標(biāo)頁,而僅是執(zhí)行腳本。

我們添加這些工具方法到主要的對象上,并準(zhǔn)備開始:

javascript:

slideshow = {
    current:0, // 當(dāng)前幻燈片編碼
    init:function(){
        // 初始化和設(shè)置事件處理函數(shù)
    },
    show:function(e){
        // 事件監(jiān)聽器
    },
    addevent:function( obj, type, fn ) {
        if ( obj.attachevent ) {
            obj['e'+type+fn] = fn;
            obj[type+fn] = function(){
                obj['e'+type+fn]( window.event );
            }
            obj.attachevent(’on’+type, obj[type+fn] );
        } else
            obj.addeventlistener( type, fn, false );
    },
    removeclass:function(o,c){
        var rep=o.classname.match(’ ‘+c)?’ ‘+c:c;
        o.classname=o.classname.replace(rep,”);
    },
    addclass:function(o,c){
        var test = new regexp(”(^|//s)”+c+”(//s|$)”).test(o.classname);
        if(!test){o.classname+=o.classname?’ ‘+c:c;}
    },
    cancelclick:function(e){
        if (window.event){
            window.event.cancelbubble = true;
            window.event.returnvalue = false;
        }
        if (e && e.stoppropagation && e.preventdefault){
            e.stoppropagation();
            e.preventdefault();
        }
    }
}

當(dāng)文檔完全載完,第一件事情就是需要執(zhí)行 init() 方法:

javascript:

slideshow = {
    current:0, // 當(dāng)前幻燈片編碼
    init:function(){
        // 初始化和設(shè)置事件處理函數(shù)
    },
    show:function(e){
        // 事件監(jiān)聽器
    },
    addevent:function( obj, type, fn ) {
        if ( obj.attachevent ) {
            obj['e'+type+fn] = fn;
            obj[type+fn] = function(){
                obj['e'+type+fn]( window.event );
            }
            obj.attachevent(’on’+type, obj[type+fn] );
        } else
            obj.addeventlistener( type, fn, false );
    },
    removeclass:function(o,c){
        var rep=o.classname.match(’ ‘+c)?’ ‘+c:c;
        o.classname=o.classname.replace(rep,”);
    },
    addclass:function(o,c){
        var test = new regexp(”(^|//s)”+c+”(//s|$)”).test(o.classname);
        if(!test){o.classname+=o.classname?’ ‘+c:c;}
    },
    cancelclick:function(e){
        if (window.event){
            window.event.cancelbubble = true;
            window.event.returnvalue = false;
        }
        if (e && e.stoppropagation && e.preventdefault){
            e.stoppropagation();
            e.preventdefault();
        }
    }
}
slideshow.addevent(window,’load’,slideshow.init);

|||

第四步:腳本(the script)

現(xiàn)在,在適當(dāng)?shù)奈恢梦覀冇兴械姆椒üぞ撸约爱?dāng)窗口載完時被調(diào)用的 init() ,我們可以開始具體化此方法。

:這僅是 init() 方法,而不是整個腳本。因為有行號,復(fù)制并粘貼腳本將會導(dǎo)致錯誤。

 1: init:function(){
 2:     if(document.getelementbyid && document.createtextnode){
 3:         var list = document.getelementbyid(' ');
 4:         if(list){
 5:             slideshow.items = list.getelementsbytagname('li');
 6:             slideshow.all = slideshow.items.length;
 7:             if(slideshow.all > 1){
 8:                 slideshow.addclass(list, 'js');
 9:                 slideshow.createnav(list);
10:            }
11:         }
12:         slideshow.show();
13:     }
14: },

  1. 第2行,檢測 dom 是否被支持。
  2. 第3和4行,嘗試檢索 id 為 slideshow 的元素,如果沒有被定義則不執(zhí)行余下的方法。
  3. 第5和6行,檢索列表項及列表項的個數(shù),并分別儲存在屬性 items 和 all 里。
  4. 第7行,檢測是否超多一個列表項,如果不超多則不執(zhí)行余下的。
  5. 第8行,添加 js 樣式類名到列表上,從而隱藏列表項和應(yīng)該不同的樣式。
  6. 第9行,調(diào)用 createnav(),并提供這個列表作為參數(shù)。
  7. 第12行,調(diào)用 show() 用來顯示預(yù)定義了 current 屬性的滑動門。

createnav() 方法使用 dom 腳本創(chuàng)建幻燈片正常工作所需的 html。

 1: createnav:function(o){
 2:     var p = document.createelement('p');
 3:     slideshow.addclass(p, 'slidenav');
 4:     slideshow.prev = document.createelement('a');
 5:     slideshow.prev.setattribute('href', '#');
 6:     var templabel = document.createtextnode('<<');
 7:     slideshow.prev.appendchild(templabel);
 8:     slideshow.addevent(slideshow.prev, 'click', slideshow.show);
 9:     p.appendchild(slideshow.prev);
10:     slideshow.count = document.createelement('span');
11:     templabel = document.createtextnode( (slideshow.current+1) + ' / ' + slideshow.all);
12:     slideshow.count.appendchild(templabel);
13:     p.appendchild(slideshow.count);
14:     slideshow.next = document.createelement('a');
15:     slideshow.next.setattribute('href', '#');
16:     var templabel = document.createtextnode('>>’);
17:     slideshow.next.appendchild(templabel);
18:     slideshow.addevent(slideshow.next, ‘click’, slideshow.show);
19:     p.appendchild(slideshow.next);
20:     o.parentnode.insertbefore(p, o);
21: },

  1. 第2和3行,剛開始創(chuàng)建一個 p 元素,用來包含整個幻燈片導(dǎo)航,并應(yīng)用一個名為 slidenav 的 class。
  2. 第4和5行,創(chuàng)建一個新的鏈接元素,儲存在叫 prev 的屬性中,設(shè)置 href 屬性為 #。使鏈接顯示為一個真正的鏈接且鍵盤可用,是有必要的。
  3. 第6行,創(chuàng)建一個新的文本標(biāo)簽。
  4. 第7行,將文本標(biāo)簽添加到鏈接上。
  5. 第8行,添加一個事件處理函數(shù),指向 show() 監(jiān)聽方法。
  6. 第9行,將新的鏈接添加到 段落上。
  7. 第10行,開始計數(shù)器,我們創(chuàng)建一個 span 元素,并用 count 屬性儲存他。
  8. 第11行,創(chuàng)建一個新的文本節(jié)點,顯示當(dāng)前幻燈片在總數(shù)中的位置。我們需要給當(dāng)前的屬性增加 1,因為人類計數(shù)是從 1 開始而非從 0。
  9. 第12行,將文本作為新的子節(jié)點,添加至 span 上 。
  10. 第13行,將 span 元素 添加到段落上。
  11. 第14至19行,基本上是復(fù)制 4 到 9 行,這次重新創(chuàng)建鏈接唯一不同的是文本標(biāo)簽,他儲存在 next 屬性上。
  12. 第20行,將最近創(chuàng)建的段落插入到文檔中初始的圖片列表前。

這些被創(chuàng)建的所有標(biāo)記都是必要的,最后剩下的是去定義一個當(dāng)鏈接被點擊時調(diào)用的監(jiān)聽方法 show() 。

 1: show:function(e){
 2:     if(this === slideshow.next || this === slideshow.prev){
 3:         slideshow.removeclass(slideshow.items[slideshow.current], ‘current’);
 4:         var addto = (this === slideshow.next) ? 1 : -1;
 5:         slideshow.current = slideshow.current + addto;
 6:         if(slideshow.current < 0){
 7:             slideshow.current = (slideshow.all-1);
 8:         }
 9:         if(slideshow.current > slideshow.all-1){
10:             slideshow.current = 0;
11:         }
12:     }
13:     var templabel = document.createtextnode((slideshow.current+1) + ‘ / ‘ + slideshow.all);
14:     slideshow.count.replacechild(templabel, slideshow.count.firstchild);
15:     slideshow.addclass(slideshow.items[slideshow.current], ‘current’);
16:     slideshow.cancelclick(e);
17: },

  1. 第1行,得到作為參數(shù) e 的當(dāng)前事件對象,這是稍后調(diào)用的 cancelclick() 唯一需要。
  2. 第2行,檢測點擊的元素是否是向下或者向前鏈接(this 由 addevent() 返回)。
  3. 第3行,從當(dāng)前顯示的幻燈片上移除 current 的 class。由于現(xiàn)在有一個被點擊的鏈接,這將成為可能。
  4. 第4行,通過比較 this 和 next 屬性,決定 current 的計數(shù)器是應(yīng)該增加還是減少。
  5. 第5行,修正計數(shù)器。
  6. 第6到11行,確定計數(shù)器將永遠不會超出范圍,當(dāng)你在第一幻燈片并點擊了向前的鏈接,將設(shè)置他為最后一個,而當(dāng)你在最后一個幻燈片,點擊了向后的鏈接,將設(shè)置為第一個。
  7. 第13和14行,生成一個新的計數(shù)器文本并替代舊的。
  8. 第15行,通過設(shè)置名為 current 的 class,顯示新的當(dāng)前幻燈片。
  9. 第16行,通過調(diào)用 cancelclick() 阻止鏈接的默認行為。

這些是腳本的所有內(nèi)容。現(xiàn)在這個腳本可以工作,但仍不是真正可維護的。

|||

第五步:輕松維護(easing maintenance)

腳本功能齊全,分離式而且無懈可擊。真正的問題是,現(xiàn)在并不方便維護。

腳本應(yīng)用的最大的問題大概是,并不是所有的維護者都懂 javascript 和愿意在你的腳本中尋找需要修改的部分。

為了避免維護者做這些,最安全的方法就是把腳本和 css 中使用的命名和 id 從你的腳本功能中分離出來。此外,從使用的腳本中分離出文本標(biāo)簽也是個好點子,因為他們可能會改變。例如,當(dāng)腳本使用其他語言本地化時。

工具方法的復(fù)用

第一件要做的事情就是,從主要腳本中分離出其他腳本也可以再用的工具函數(shù)。這也許是大部分 javascript 庫的開始。

tools.js:

/* 輔助方法 */
tools = {
    addevent:function( obj, type, fn ) {
        if ( obj.attachevent ) {
            obj['e'+type+fn] = fn;
            obj[type+fn] = function(){
                obj['e'+type+fn]( window.event );
            }
            obj.attachevent( ‘on’+type, obj[type+fn] );
        } else
            obj.addeventlistener( type, fn, false );
        },
    removeclass:function(o,c){
        var rep=o.classname.match(’ ‘+c)?’ ‘+c:c;
        o.classname=o.classname.replace(rep,”);
    },
    addclass:function(o,c){
        var test = new regexp(”(^|//s)” + c + “(//s|$)”).test(o.classname);
        if(!test){o.classname+=o.classname?’ ‘+c:c;}
    },
    cancelclick:function(e){
        if (window.event){
            window.event.cancelbubble = true;
            window.event.returnvalue = false;
        }
        if (e && e.stoppropagation && e.preventdefault){
            e.stoppropagation();
            e.preventdefault();
        }
    }
}

css 的 class 和 id —— 外觀

下一步要做的是,分離外觀的 class 和 id 到一個單獨的包含文件。保證他們在 slideshow 命名空間里是安全的,因為其他腳本不太可能用到他們。也不會妨礙寫一個簡短的說明注釋。

slideshow-css.js:

slideshow.css = {
    /*
    這些都是幻燈片效果中使用到的 classe 和 id。
    你可以在這里修改他們中的任何一個。
    務(wù)必請使用引號包圍名稱,用逗號結(jié)尾(除了最后一個)。
    */

    showid               :'slideshow',
    dynamicclass         :'js',
    slidenavigationclass :'slidenav',
    currentclass         :'current'
}

文本標(biāo)簽(text labels)—— 解釋給終端用戶

最后但不是最不重要的,讓我們將文本標(biāo)簽放到一個單獨的包含文件,再次使用 slideshow 命名空間。

slideshow-labels.js:

slideshow.labels = {
    /*
    這些都是幻燈片效果中使用到文本標(biāo)簽。
    你可以在這里修改他們中的任何一個。
    務(wù)必請使用引號包圍名稱。
    最后一個結(jié)尾不用逗號。
    */

    previous       : '<<',
    next           : '>>’,
    counterdivider : ‘ of ‘
}

改變的主要腳本

然后,我們需要修改主要腳本使用此信息,而不是依賴嵌入式的數(shù)據(jù)。沒有太多的改變,很容易用搜索加替換就能做到。

slideshow.js:

slideshow = {
    current:0,
    init:function(){
        if(document.getelementbyid && document.createtextnode){
            var list =document.getelementbyid(slideshow.css.showid);
            if(list){
                slideshow.items = list.getelementsbytagname('li');
                slideshow.all = slideshow.items.length;
                if(slideshow.all > 1){
                    tools.addclass(list, slideshow.css.dynamicclass);
                    slideshow.createnav(list);
                }
            }
            slideshow.show();
        }
     },
    createnav:function(o){
        var p = document.createelement('p');
        tools.addclass(p, slideshow.css.slidenavigationclass);
        slideshow.prev = document.createelement('a');
        slideshow.prev.setattribute('href', '#');
        var templabel = document.createtextnode(slideshow.labels.previous);
        slideshow.prev.appendchild(templabel);
        tools.addevent(slideshow.prev, 'click', slideshow.show);
        p.appendchild(slideshow.prev);
        slideshow.count = document.createelement('span');
        templabel =document.createtextnode((slideshow.current+1) + slideshow.labels.counterdivider + slideshow.all);
        slideshow.count.appendchild(templabel);
        p.appendchild(slideshow.count);
        slideshow.next = document.createelement('a');
        slideshow.next.setattribute('href', '#');
        var templabel = document.createtextnode(
        slideshow.labels.next);
        slideshow.next.appendchild(templabel);
        tools.addevent(slideshow.next, 'click', slideshow.show);
        p.appendchild(slideshow.next);
        o.parentnode.insertbefore(p, o);
    },
    show:function(e){
        if(this === slideshow.next || this === slideshow.prev){
            tools.removeclass(slideshow.items[slideshow.current],
            slideshow.css.currentclass);
            var addto = this === slideshow.next ? 1 : -1;
            slideshow.current = slideshow.current + addto;
            if(slideshow.current < 0){
                slideshow.current = (slideshow.all-1);
            }
            if(slideshow.current > slideshow.all-1){
                slideshow.current = 0;
            }
        }
        var templabel = document.createtextnode((slideshow.current+1) + slideshow.labels.counterdivider + slideshow.all);
        slideshow.count.replacechild(templabel, slideshow.count.firstchild);
        tools.addclass(slideshow.items[slideshow.current], slideshow.css.currentclass);
        tools.cancelclick(e);
    }
}
tools.addevent(window,’load’,slideshow.init);

這些所有文件是確保將來維護者不用麻煩你就可以使用你的腳本工作所需要的。文件名應(yīng)該很明顯,是什么就是什么,并能隨著時間的推移,成為一個標(biāo)準(zhǔn)的腳本:

tools.js
slideshow.js
slideshow-labels.js
slideshow-css.js
slideshow.css

原作者:christian heilmann   譯者:懌飛
原文:《a detailed explanation how to create a maintainable dynamic slide show in javascript》

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 吉首市| 仁化县| 富锦市| 上虞市| 屏东县| 南通市| 宁城县| 福安市| 慈利县| 黔东| 电白县| 伊通| 乌鲁木齐县| 固阳县| 和平区| 保靖县| 乌拉特后旗| 资溪县| 尚志市| 都匀市| 周口市| 雷波县| 南靖县| 砚山县| 德安县| 济南市| 武冈市| 芜湖市| 汝南县| 瑞金市| 罗源县| 利津县| 曲阳县| 竹北市| 保山市| 新野县| 长顺县| 灵武市| 清河县| 法库县| 皋兰县|