簡(jiǎn)單輪播圖的實(shí)現(xiàn)及原理講解(js)

0.最終效果預(yù)覽

鼠標(biāo)未觸及區(qū)域時(shí)(自動(dòng)滾動(dòng)中)
鼠標(biāo)觸及區(qū)域后 (停止?jié)L動(dòng)漠魏,顯示按鈕)
基本功能
  • 自動(dòng)無(wú)縫滾動(dòng)
  • 左右按鈕控制滾動(dòng)
  • 點(diǎn)擊圓點(diǎn)切換圖片

1.整體結(jié)構(gòu)與思路

Html部分

<body>
    <div id= "parent">
        <div id="uls">
            <ul id="img_ul">
                <li><img src="imgs/0.jpg"/></li>
                <li><img src="imgs/1.jpg"/></li>
                <li><img src="imgs/2.jpg"/></li>
                <li><img src="imgs/3.jpg"/></li>
                <li><img src="imgs/4.jpg"/></li>
            </ul>
            <ul id='litCir_ul'></ul>
        </div>
        <div id="buttons">
            <span id="left">&lt;</span>
            <span id="right">&gt;</span>
        </div>
    </div>
</body>

三個(gè)div,最外層id為parent的大div內(nèi)包含了ulsbuttons兩個(gè)div予颤,divuls中包含了兩個(gè)列表img_ul(圖片列表), litCir_ul(小圓點(diǎn)列表)涝婉,divbuttons里則包含了“左”劲件, “右”兩個(gè)按鈕未巫。

CSS部分

#parent{
    position: relative;
    margin: 50px auto;
    padding: 0;
    width: 500px;
    height: 309px;
}

#uls{
    position: relative;
    margin: 0;
    padding: 0;
    width: 500px;
    height: 309px;
    overflow: hidden;
}

#img_ul{
    position: absolute;
    margin: 0;
    padding: 0;
    left: 0;
    top: 0;
    width: 3000px;           /*多留出一張圖片的寬度!*/
    list-style: none;
}
#img_ul li{
    float: left;
    margin: 0;
    padding: 0;
    width: 500px;
    height: 309px;
}
#img_ul li img{
    width: 500px;
    height: 309px;
}

#litCir_ul{
    position: absolute;
    margin: 0;
    padding: 0;
    right: 10px;
    bottom: 10px;
    list-style: none;
}
#litCir_ul li{
    margin: 0;
    padding: 0;
    float: left;
    width: 20px;
    height: 20px;
    text-align: center;
    line-height: 20px;
    border-radius: 50%; 
    margin-left:10px ;
    cursor: pointer;
}

li.active{
    background-color: white;
}
li.quiet{
    background-color: #1e90ff;
}

#buttons{
    margin: 0;
    padding: 0;
    display: none;
}
#buttons span{
    position: absolute;
    width: 40px;
    height: 40px;
    top: 50%;
    margin-top: -20px;
    line-height: 40px;
    text-align: center;
    font-weight: bold;
    font-family: Simsun;
    font-size: 30px;
    border: 1px solid #fff;
    opacity: 0.3;
    cursor: pointer;
    color: #fff;
    background: black;
}
#left{
    left: 5px;
}
#right{
    left: 100%;
    margin-left: -45px;
}

需要注意的地方

  • 圖片的寬蔗草,高度應(yīng)和img_ul中的li標(biāo)簽咒彤, 以及div#parent疆柔, div#uls的寬,高度一致镶柱。
  • img_ul的寬度應(yīng)為(圖片數(shù)目+1)*每張圖片的寬度旷档。也就是要多留出一張圖片的寬度(下一部分解釋)。
  • div uls部分使用overflow:hidden隱藏img_ul超出的部分歇拆,確保每次該區(qū)域只能顯示一張完整的圖片鞋屈。

2.功能實(shí)現(xiàn)(JS部分)

①將會(huì)在下面用到的Html中的對(duì)象和一些變量

    /*獲取HTML中的對(duì)象*/
    var parent = document.getElementById("parent");
    var img_ul = document.getElementById("img_ul");
    var litCir_ul = document.getElementById("litCir_ul");
    var buttons = document.getElementById("buttons");
    var cLis =litCir_ul.children;

    var len = img_ul.children.length;     //圖片張數(shù)
    var width = parent.offsetWidth;       //每張圖片的寬度
    var rate = 15;                        //一張圖片的切換速度, 單位為px
    var times = 1;                        //切換速度的倍率
    var gap = 2000;                       //自動(dòng)切換間隙故觅, 單位為毫秒
    var timer = null;                     //初始化一個(gè)定時(shí)器
    var picN = 0;                         //當(dāng)前顯示的圖片下標(biāo)
    var cirN = 0;                         //當(dāng)前顯示圖片的小圓點(diǎn)下標(biāo)
    var temp;

②添加小圓點(diǎn)

之所用js添加小圓點(diǎn)厂庇,是因?yàn)樾A點(diǎn)的數(shù)量是由圖片張數(shù)決定的。

    for (var i=0; i<len; i++){
        var a_li = document.createElement("li");
        a_li.className = 'quiet';
        litCir_ul.appendChild(a_li);
    }
    litCir_ul.children[0].className = "active";

默認(rèn)liclassquiet, 第一張默認(rèn)為active输吏。

③無(wú)縫滾動(dòng)是怎么實(shí)現(xiàn)的权旷?

首先先理解該輪播圖如何滾動(dòng),這里是通過(guò)控制img_ulleft值來(lái)控制顯示某張圖片评也, 為了實(shí)現(xiàn)“滾動(dòng)”的效果炼杖,我們需要逐漸改變img_ulleft值灭返,而不能直接使該值變化圖片寬度的倍數(shù)盗迟。這里我們定義一個(gè)動(dòng)畫效果函數(shù)Roll()

function Roll(distance){                                         //參數(shù)distance:滾動(dòng)的目標(biāo)點(diǎn)(必為圖片寬度的倍數(shù))
clearInterval(img_ul.timer);                                     //每次運(yùn)行該函數(shù)必須清除之前的定時(shí)器熙含!
var speed = img_ul.offsetLeft < distance ?  rate : (0-rate);     //判斷圖片移動(dòng)的方向

img_ul.timer = setInterval(function(){                           //設(shè)置定時(shí)器罚缕,每隔10毫秒,調(diào)用一次該匿名函數(shù)
    img_ul.style.left = img_ul.offsetLeft + speed + "px";        //每一次調(diào)用滾動(dòng)到的地方 (速度為 speed px/10 ms)         
    var leave = distance - img_ul.offsetLeft;                    //距目標(biāo)點(diǎn)剩余的px值      
    /*接近目標(biāo)點(diǎn)時(shí)的處理怎静,滾動(dòng)接近目標(biāo)時(shí)直接到達(dá)邮弹, 避免rate值設(shè)置不當(dāng)時(shí)不能完整顯示圖片*/
    if (Math.abs(leave) <= Math.abs(speed)) {                    
        clearInterval(img_ul.timer);
        img_ul.style.left = distance + "px";
    }
},10);
}

試想下面的情況,當(dāng)圖片從最后一張切換到第一張時(shí)蚓聘,這時(shí)就不能通過(guò)逐漸改變img_ulleft值來(lái)實(shí)現(xiàn)滾動(dòng)的效果腌乡,于是克隆第一張圖片至列表尾部,當(dāng)滾動(dòng)完最后一張圖片時(shí)夜牡,繼續(xù)滾動(dòng)到克隆的第一張与纽,然后將img_ulleft值置為0。

    /*克隆第一個(gè)li到列表末*/
    img_ul.appendChild(img_ul.children[0].cloneNode(true));

④自動(dòng)滾動(dòng)

function autoRun(){
    picN++;
    cirN++;
    if(picN > len){                  //滾動(dòng)完克隆項(xiàng)后
        img_ul.style.left = 0;       //改變left至真正的第一項(xiàng)處
        picN = 1;                    //從第二張開始顯示
    }
    Roll(-picN*width);
    
    if(cirN > len-1){                //判斷是否到了最后一個(gè)圓點(diǎn)
        cirN = 0;                 
    }
    for(var i=0; i<len; i++){
        cLis[i].className = "quiet";
    }
    cLis[cirN].className = "active";
}

需要注意的是小圓點(diǎn)和圖片列表的li數(shù)目是不一樣的塘装,當(dāng)滾動(dòng)到最后一個(gè)克隆項(xiàng)時(shí)急迂,此時(shí)小圓點(diǎn)實(shí)際上在第一個(gè)位置。

開始自動(dòng)滾動(dòng):
timer = setInterval(autoRun, gap);

⑤觸及小圓點(diǎn)時(shí)切換至對(duì)應(yīng)圖片

    for(var i=0; i<len; i++){
        cLis[i].index = i;
        cLis[i].onmouseover = function(){
            for(var j=0; j<len; j++){
                cLis[j].className = "quiet";
            }
            this.className = "active";
            temp = cirN;
            picN = cirN = this.index;
            times = Math.abs(this.index - temp);  //距離上個(gè)小圓點(diǎn)的距離
            rate = rate*times;                    //根據(jù)距離改變切換速率
            Roll(-this.index * width);
            rate = 15;
        }
    }

給每個(gè)小圓點(diǎn)綁定了onmouseover事件蹦肴,這個(gè)方法有個(gè)細(xì)節(jié)僚碎,會(huì)根據(jù)兩次小圓點(diǎn)的距離差調(diào)整速率為rate*times,使切換效果更自然(也就是說(shuō)每次切換說(shuō)花的時(shí)間基本一致阴幌,無(wú)論是第一張到第二張勺阐,還是第一張到最后一張)卷中。

⑥觸及輪播圖區(qū)域和離開該區(qū)域時(shí)

    parent.onmouseover = function(){
        clearInterval(timer);
        buttons.style.display = 'block';
    }
    parent.onmouseout = function(){
        timer = setInterval(autoRun, gap);
        buttons.style.display = 'none';
    }

觸及區(qū)域,清除定時(shí)器皆看,顯示按鈕仓坞。
離開區(qū)域,添加定時(shí)器腰吟,隱藏按鈕无埃。

⑦給兩個(gè)按鈕添加onclick事件

    /*上一張*/
    buttons.children[0].onclick = function(){ 
        picN--;
        cirN--;
        if(picN < 0){                               //滾動(dòng)完第一項(xiàng)后
            img_ul.style.left = -len*width + "px";  //改變left至克隆的第一項(xiàng)處
            picN = cirN = len-1;
        }
        Roll(-picN*width);
        //bug處理
        if(cirN < 0){
            cirN = len-1;
        }
        for(var i=0; i<len; i++){
            cLis[i].className = "quiet";
        }
        cLis[cirN].className = "active";
    }
    /*下一張*/
    buttons.children[1].onclick = autoRun;

自動(dòng)播放就是間隔一定時(shí)間不斷調(diào)用函數(shù)“下一張”的過(guò)程,所以這里的按鈕right下一張的實(shí)現(xiàn)就是上面的autoRun函數(shù)毛雇。

以上就是輪播圖各部分的實(shí)現(xiàn)原理嫉称,如果你有其他的方法,歡迎一起交流灵疮!
2019.3.30更新:
用requestAnimationFrame()實(shí)現(xiàn)一個(gè)輪播圖

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末织阅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子震捣,更是在濱河造成了極大的恐慌荔棉,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,542評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蒿赢,死亡現(xiàn)場(chǎng)離奇詭異润樱,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)羡棵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門壹若,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人皂冰,你說(shuō)我怎么就攤上這事店展。” “怎么了秃流?”我有些...
    開封第一講書人閱讀 158,021評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵赂蕴,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我舶胀,道長(zhǎng)概说,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,682評(píng)論 1 284
  • 正文 為了忘掉前任峻贮,我火速辦了婚禮席怪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘纤控。我一直安慰自己挂捻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,792評(píng)論 6 386
  • 文/花漫 我一把揭開白布船万。 她就那樣靜靜地躺著刻撒,像睡著了一般骨田。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上声怔,一...
    開封第一講書人閱讀 49,985評(píng)論 1 291
  • 那天态贤,我揣著相機(jī)與錄音,去河邊找鬼醋火。 笑死悠汽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的芥驳。 我是一名探鬼主播柿冲,決...
    沈念sama閱讀 39,107評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼兆旬!你這毒婦竟也來(lái)了假抄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,845評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤丽猬,失蹤者是張志新(化名)和其女友劉穎宿饱,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體脚祟,經(jīng)...
    沈念sama閱讀 44,299評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谬以,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,612評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了愚铡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蛉签。...
    茶點(diǎn)故事閱讀 38,747評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡胡陪,死狀恐怖沥寥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情柠座,我是刑警寧澤邑雅,帶...
    沈念sama閱讀 34,441評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站妈经,受9級(jí)特大地震影響淮野,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吹泡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,072評(píng)論 3 317
  • 文/蒙蒙 一骤星、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧爆哑,春花似錦洞难、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)色冀。三九已至,卻和暖如春柱嫌,著一層夾襖步出監(jiān)牢的瞬間锋恬,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工编丘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留与学,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,545評(píng)論 2 362
  • 正文 我出身青樓嘉抓,卻偏偏與公主長(zhǎng)得像癣防,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子掌眠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,658評(píng)論 2 350