原生JavaScript無縫輪播圖特效

什么是輪播圖?

輪播圖辰妙,圖片旋轉(zhuǎn)器,滑片甫窟,無論你怎么叫這玩意密浑,它在網(wǎng)絡(luò)上無處不在。輪播圖在電商網(wǎng)站主頁(yè)上廣泛應(yīng)用粗井,大多數(shù)電商網(wǎng)站的主頁(yè)上都有它:

高大上的無縫輪播

本輪播圖Demo

由于仿色壓縮將就看吧6啤(手動(dòng)滑稽)

喏~兩個(gè)鏈接甩給泥萌
Github倉(cāng)庫(kù)文件
在線Demo(移動(dòng)端加載很慢)

前言

網(wǎng)上有很多的輪播圖特效,部分采用的transition屬性結(jié)合JS實(shí)現(xiàn)滾動(dòng)浇衬,但是很遺憾沒有無縫效果懒构,什么是無縫?我給前端小白畫了一個(gè)示意圖耘擂。另外本文是我寫的第一篇文章胆剧,難免有生疏之處。包含很多知識(shí)點(diǎn)回顧醉冤,很適合JS新手學(xué)習(xí)秩霍。

實(shí)際上1-5才是真正的圖片(紅色的東西是個(gè)iphone哈哈,當(dāng)作是container吧)

當(dāng)焦點(diǎn)位于圖片1時(shí)蚁阳,如果再往前滾的話铃绒,整個(gè)隊(duì)列會(huì)被拉倒真正的第五張圖。至于真正的圖片1前面的副本圖片5只是讓用戶產(chǎn)生視覺差螺捐,從而不會(huì)讓用戶明顯感覺到圖片被倒向了圖片5匿垄,看起來就像時(shí)無縫輪播。
同理當(dāng)焦點(diǎn)位于圖片5時(shí)归粉,如果再往后滾椿疗,道理同上不再贅述。

實(shí)現(xiàn)功能

1.當(dāng)鼠標(biāo)放入容器內(nèi)時(shí)左右出現(xiàn)控制按鈕糠悼,并且輪播動(dòng)畫停止届榄。
2.當(dāng)鼠標(biāo)移出時(shí),控制按鈕隱藏倔喂,輪播繼續(xù)铝条。
3.焦點(diǎn)隨圖片的滾動(dòng)而變化。
4.跳躍點(diǎn)擊焦點(diǎn)席噩,會(huì)跳轉(zhuǎn)到相應(yīng)的圖片班缰。
5.以及前沿所述的無縫輪播。

開搞~~

Html代碼:

(內(nèi)有注釋解析)

<div id="container">
    <div id="list" style="left: -600px;">//初始狀態(tài)是真正的圖片1悼枢,也就是絕對(duì)定位-600px
        ![](img/555.jpg)
        ![](img/111.jpg)
        ![](img/222.jpg)
        ![](img/333.jpg)
        ![](img/444.jpg)
        ![](img/555.jpg)
        ![](img/111.jpg)
    </div>
    <div id="buttons">
        <span index="1" class="on"></span>//動(dòng)畫開始時(shí)小圓點(diǎn)位于第一個(gè)
        <span index="2"></span>
        <span index="3"></span>
        <span index="4"></span>
        <span index="5"></span>
    </div>
    <a  id="prev" class="arrow"><</a>//前一個(gè)箭頭
    <a  id="next" class="arrow">></a>//后一個(gè)箭頭
</div>

開始講解代碼:

1.箭頭控制

var prev=document.getElementById("prev");
var next=document.getElementById("next");
var list=document.getElementById("list");
prev.onclick=function(){
                 list.style.left=parseInt(list.style.left)-600+"px";
                }
next.onclick=function(){
                 list.style.left=parseInt(list.style.left)+600+"px";
                }

給a標(biāo)簽綁定點(diǎn)擊事件埠忘,先獲取listleft屬性并且取出數(shù)字進(jìn)行運(yùn)算操作。下面我們來做一些優(yōu)化,把定義一個(gè)function animate()函數(shù)莹妒,傳入offset參數(shù)名船,并把var newLeft=parseInt(list.style.left) +offset;,然后讓prevnext的點(diǎn)擊事件調(diào)用這個(gè)函數(shù)旨怠。

function animate(offset){
                 list.style.left=newLeft+offset+"px";
            }
            prev.onclick=function(){
                animate(-600);
            }
            next.onclick=function(){
                animate(600);
            }

然后我們會(huì)發(fā)現(xiàn)當(dāng)我們點(diǎn)擊到第五張圖片left=-3000px時(shí)渠驼,它應(yīng)該滾到真正的第1張而不是副本1。我們可以像下面這樣寫實(shí)現(xiàn)無縫滾動(dòng):

function animate(offset){
 list.style.left=newLeft+offset+"px";       
if (newLeft >-600) {
 list.style.left=-3000+"px";
    };
 if (newLeft <-3000) {
list.style.left=-600+"px";
    };
 }
用箭頭控制圖片的輪播大工告成<濉C陨取(撒花~)

2.焦點(diǎn)跟隨

這個(gè)功能可能比較難以理解,其實(shí)和第一部分是一樣的爽哎。首先考慮到prev和next點(diǎn)擊事件中要有標(biāo)記蜓席,這個(gè)標(biāo)記就是一個(gè)掛鉤,再定義一個(gè)函數(shù)利用這個(gè)掛鉤來跟隨焦點(diǎn)倦青。我們用showButton()函數(shù),全局定義變量var index=1先讓第一幅圖的焦點(diǎn)亮起來。下面我們來看代碼(忽略animate變量盹舞,下一部分我們會(huì)講到):

var buttons=document.getElementById("buttons").getElementsByTagName("span");
var index=1//buttons[0].classNme="on";
 var animated=false;//全局動(dòng)畫停止標(biāo)記
function shownButton(){
 /* for循環(huán)的作用就是當(dāng)prev和next每click一次产镐,
 就會(huì)清除一次前一個(gè)class為on的span元素*/
                 for (var i = 0; i < buttons.length ; i++) {
                     buttons[i].className="";      
                }
           buttons[index -1].className="on";//焦點(diǎn)跟隨
            } 
prev.onclick=function(){
                if (!animated) {//這里判斷
                if (index==1) {
/*這就是我們下面要講到的當(dāng)焦點(diǎn)位于第一個(gè)span時(shí)踢步,讓它跳轉(zhuǎn)到第5個(gè)*/
                    index=5;
                }else {
                   index -=1; 
                }
                
                shownButton();//把上一個(gè)亮起的滅掉癣亚,下一個(gè)亮起
                     animate(600);
                }
            };
            next.onclick=function(){   
                if (!animated) {/*全局變量animated=false,那么获印!animated=true
                     if (index==5) {
                    index=1;
                }else {
                   index +=1; 
                }    
                     shownButton();
                     animate(-600);
                }
            };

3.焦點(diǎn)輪播(實(shí)現(xiàn)功能第四點(diǎn))

當(dāng)圖片位于第一個(gè)焦點(diǎn)時(shí)述雾,我點(diǎn)擊第四的焦點(diǎn)。left=-600px變成了left=-2400px話不多說兼丰,來看下面的代碼吧玻孟。

 for (var i = 0; i < buttons.length; i++) {
                buttons[i].onclick=function(){
                    //無關(guān)緊要,性能優(yōu)化使用鳍征,目的是當(dāng)index和myindex相等時(shí)黍翎,退出函數(shù)
                    if (this.className=="on") {
                        return;
                    }
                    var myIndex=parseInt(this.getAttribute("index"));//index不是a的固有屬性,因此要用dom調(diào)用
                    var offset=-600*(myIndex-index);
                     if (!animated) {/*又出現(xiàn)了這個(gè)animated艳丛,
在此意思是如果animate()執(zhí)行過程中匣掸,animated=true,那么animate()不能再次被 調(diào)用*/
                     animate(offset);
                }
                    index=myIndex;//更新index氮双,便于下一次的輪播
                     shownButton();               
                }
            }           

4.動(dòng)畫函數(shù)

動(dòng)畫函數(shù)go()整合到了animate()函數(shù)里了碰酝。只可意會(huì)不可言傳(手動(dòng)滑稽)直接上代碼吧:

function animate(offset){ 
             
                var speed = offset/30;//每次的位移,分母越大越流暢
                  animated=true;//動(dòng)畫正在運(yùn)行戴差,別的事件不要來打擾
                 var newLeft=parseInt(list.style.left) +offset;
                function go(){
                    if ( (speed > 0 && parseInt(list.style.left) < newLeft) || (speed < 0 && parseInt(list.style.left) > newLeft)) {
                        list.style.left = parseInt(list.style.left) + speed + 'px';
                        setTimeout(go, inteval);//遞歸函數(shù)
                    }
                    else 
                    {       
                       animated=false;
                     list.style.left=newLeft+"px";
                         if (newLeft >-600) {
                     list.style.left=-3000+"px";
                         };
                        if (newLeft <-3000) {
                     list.style.left=-600+"px";
                      };
                    }
                }
                go();
            };     

5.定時(shí)器

HTML DOM setInterval() 方法

var container=document.getElementById("container");
var timer;
function play(){
                timer=setInterval(function(){
                    next.onclick();
                },2000);
            }
            function stop(){
                clearInterval(timer);
            }
           play();
        container.onmouseover=stop;
        container.onmouseout=play;

最后放一遍總的JS代碼

高大上的JS代碼(滑稽)
< script > 
window.onload = function () 
{
    var prev = document.getElementById("prev");
    var next = document.getElementById("next");
    var list = document.getElementById("list");
    var buttons = document.getElementById("buttons").getElementsByTagName("span");
    var container = document.getElementById("container");
    var index = 1;
    var timer;
    var animated = false;
    function shownButton()
    {
        for (var i = 0; i < buttons.length ; i++) 
        {
            if ( buttons[i].className == 'on')
            {
                buttons[i].className = '';
                /* prev和next每click一次送爸,
                        就會(huì)清除一次前一個(gè)class為on的span元素,
                        所以沒有必要再去循環(huán)下面的span*/
                break;
            }
            //  或者直接遍歷清除  buttons[i].className="";
        }
        buttons[index - 1].className = "on";
    }
    function animate(offset)
    {
        var time = 300;
        var inteval = 10;
        var speed = offset / (time / inteval);
        animated = true;//更改全局變量碱璃,防止跳圖
        var newLeft = parseInt(list.style.left) + offset;
        function go()
        {
            if ( (speed > 0 && parseInt(list.style.left) < newLeft) || (speed < 0 && parseInt(list.style.left) > newLeft)) {
                list.style.left = parseInt(list.style.left) + speed + 'px';
                setTimeout(go, inteval);
            }
            else 
            {
                animated = false;//全局變量
                 list.style.left=newLeft+"px";
                if (newLeft > -600) {
                    list.style.left =- 3000 + "px";
                };
                if (newLeft <- 3000) {
                    list.style.left =- 600 + "px";
                };
            }
        }
        go();
    };
    prev.onclick = function ()
    {
        /*添加一個(gè)if判斷index為1時(shí)弄痹,如果繼續(xù)往前滾的話就讓index返回第五個(gè)span
                但是當(dāng)快速點(diǎn)擊arrow時(shí)會(huì)出現(xiàn)一種span點(diǎn)亮延遲的情況∏镀鳎可以嘗試把判斷index是否大于1或小于5的情況放進(jìn)
                判斷是否animated的if語(yǔ)句中肛真,先判斷能不能點(diǎn)擊,再點(diǎn)亮爽航。
                */
        if (!animated) {
            if (index == 1) {
                index = 5;
            }
            else {
                index -= 1;
            }
            shownButton();
            animate(600);
        }
    };
    next.onclick = function ()
    {
        if (!animated) {
            if (index == 5) {
                index = 1;
            }
            else {
                index += 1;
            }
            shownButton();
            animate(-600);
        }
    };
    for (var i = 0; i < buttons.length; i++) 
    {
        buttons[i].onclick = function ()
        {
            //無關(guān)緊要
            if (this.className == "on") {
                return;
            }
            var myIndex = parseInt(this.getAttribute("index"));
            var offset =- 600 * (myIndex - index);
            if (!animated) {
                animate(offset);
            }
            index = myIndex;
            shownButton();
        }
    }
    function play()
    {
        timer = setInterval(function ()
        {
            next.onclick();
        }, 2000);
    }
    function stop()
    {
        clearInterval(timer);
    }
    play();
    container.onmouseover = stop;
    container.onmouseout = play;
}
 </script>

總結(jié)

其實(shí)寫這種技術(shù)性文章最能考驗(yàn)?zāi)闶欠窭斫饬诉@個(gè)特效蚓让,同時(shí)也是最累的。昨天晚上我在跟著慕課網(wǎng)做的時(shí)候讥珍,有一瞬間想放棄了历极,畢竟現(xiàn)在框架那么多,何必那么絞盡腦汁用一個(gè)復(fù)雜的函數(shù)做動(dòng)畫呢衷佃,直接引用JS庫(kù)多省事趟卸。但是直到我寫完這篇教程,我很慶幸我堅(jiān)持下來了氏义。這是我的第一篇文章锄列,簡(jiǎn)書提供了一個(gè)很棒的平臺(tái)來記錄一個(gè)平凡人的世界。以后會(huì)常來這里惯悠,分享自己的所得邻邮,這也是一種喜悅。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末克婶,一起剝皮案震驚了整個(gè)濱河市筒严,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌情萤,老刑警劉巖鸭蛙,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異筋岛,居然都是意外死亡规惰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門泉蝌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來歇万,“玉大人,你說我怎么就攤上這事勋陪√盎牵” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵诅愚,是天一觀的道長(zhǎng)寒锚。 經(jīng)常有香客問我劫映,道長(zhǎng),這世上最難降的妖魔是什么刹前? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任泳赋,我火速辦了婚禮,結(jié)果婚禮上喇喉,老公的妹妹穿的比我還像新娘祖今。我一直安慰自己,他們只是感情好拣技,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布千诬。 她就那樣靜靜地躺著,像睡著了一般膏斤。 火紅的嫁衣襯著肌膚如雪徐绑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天莫辨,我揣著相機(jī)與錄音傲茄,去河邊找鬼。 笑死沮榜,一個(gè)胖子當(dāng)著我的面吹牛盘榨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播敞映,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼较曼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼磷斧!你這毒婦竟也來了振愿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤弛饭,失蹤者是張志新(化名)和其女友劉穎冕末,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體侣颂,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡档桃,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了憔晒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片藻肄。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖拒担,靈堂內(nèi)的尸體忽然破棺而出嘹屯,到底是詐尸還是另有隱情,我是刑警寧澤从撼,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布州弟,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏婆翔。R本人自食惡果不足惜拯杠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望啃奴。 院中可真熱鬧潭陪,春花似錦、人聲如沸纺腊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)揖膜。三九已至誓沸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間壹粟,已是汗流浹背拜隧。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留趁仙,地道東北人洪添。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像雀费,于是被迫代替她去往敵國(guó)和親干奢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,504評(píng)論 25 707
  • 通過學(xué)習(xí)盏袄,我理解了圖片輪播原理忿峻,學(xué)習(xí)了setTimeout()、setInterval()函數(shù)設(shè)置定時(shí)器與清除定時(shí)...
    McRay閱讀 2,123評(píng)論 0 7
  • 進(jìn)入前端將近一年了辕羽,js還是很弱逛尚,突發(fā)奇想寫一個(gè)輪播圖,就找到了這個(gè)博主的材料刁愿,和大家分享绰寞。 輪播圖的原理: 一系...
    FRRRR閱讀 3,654評(píng)論 0 11
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件铣口、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,024評(píng)論 4 62
  • 壽司店的老板娘(一)壽司店的老板娘(二) (續(xù)上)有一天滤钱,我們猶豫著晚上吃什么。 “我們?nèi)フ依习迥锇伞薄昂冒 ?于...
    珉思苦想閱讀 840評(píng)論 0 0