原生js實(shí)現(xiàn)輪播圖的組件化

本文首發(fā)于我的博客這是我的github,歡迎star。

這是一個(gè)輪播圖組件,你可以直接下載使用,這里是代碼地址,需要傳入容器的id和圖片地址,支持Internet Explorer 10+FirefoxOperaChrome等現(xiàn)代瀏覽器。

之前寫一些功能或是特效都是寫在一個(gè)個(gè)函數(shù)里,可能因?yàn)槲沂怯?code>c語(yǔ)言入門編程,所以更傾向于面向過(guò)程的編程方式,沒(méi)有想過(guò)將一個(gè)模塊抽象成為對(duì)象,做成組件。但是由于嘗到了重復(fù)造輪子之苦。我決定將不可復(fù)用的代碼做成組件,提高編程效率。以下就是我做輪播圖組件的全部過(guò)程,由于是第一次寫組件,如果有哪里思維不對(duì),或?qū)懙姆绞接袉?wèn)題,還希望不吝賜教,共同學(xué)習(xí)。

首先看一下如何使用這個(gè)組件,用到了font-awesome圖標(biāo)庫(kù),然后調(diào)用輪播圖的css,最后是用戶自己的css,用戶必須設(shè)置容器id以及容器寬高,否則無(wú)法正常顯示。生成輪播圖時(shí)給構(gòu)造函數(shù)傳入容器元素,以及圖片地址:

<head>
    <meta charset="UTF-8">
    <title>輪播圖</title>
    <link rel="stylesheet" href="css/font-awesome.min.css">
    <link rel="stylesheet" href="css/carousel.css">
    <link rel="stylesheet" href="css/user-index.css">
</head>

<body>
    <div id="carousel"></div>           
    <div id="other"></div>
    <script src="js/carousel.js"></script>
    <script>
        var carousel = new Carousel({
            wrap: document.getElementById("carousel"),
            urlArr: ["img/1.jpg", "img/2.jpg", "img/3.jpg"]
        });
        var other = new Carousel({
            wrap: document.getElementById("other"),
            urlArr: ["img/4.jpg", "img/5.jpg", "img/6.jpg"]
        });
    </script>
</body>

下邊我們看下具體實(shí)現(xiàn)。首先是輪播圖的構(gòu)造函數(shù):

function Carousel(obj) {
    this.wrap = obj.wrap;
    this.wrapId = obj.wrap.id;              //容器的id
    this.wrapWidth = this.wrap.offsetWidth; //容器寬
    this.imgNumber = obj.urlArr.length;     //圖片數(shù)
    this.activePage = 0;                    //輪播圖當(dāng)前頁(yè)
    this.settimeID;                         //定時(shí)器id
    this.init(obj.urlArr);
}

基本思路就是在構(gòu)造函數(shù)里寫入輪播圖的實(shí)例屬性,不同的輪播圖具有不同的實(shí)例屬性,將其共同擁有的方法寫成原型屬性,完整代碼請(qǐng)到github上查看,喜歡的可以順手給個(gè)星。原型對(duì)象的基本結(jié)構(gòu)如下所示:

Carousel.prototype = {
    constructor: Carousel,                  //構(gòu)造函數(shù)指向原函數(shù)
    init: function(urlArr){},               //構(gòu)建DOM結(jié)構(gòu)
    bindEvent: function(){},                //綁定事件
    pageActiveColor: function(){},          //繪制圓點(diǎn)
    leftAngleclick: function(){},           //點(diǎn)擊左箭頭
    rightAngleclick: function(){},
    selectPage: function(selectNum){},      //點(diǎn)擊圓點(diǎn)定位到指定圖片
    setTime: function(){},                  //自動(dòng)播放
    clearTime: function(){}                 //鼠標(biāo)懸浮取消自動(dòng)播放
}

建立dom結(jié)構(gòu)的代碼如下,根據(jù)容器的id生成后代dom節(jié)點(diǎn)的id以及class,然后在css中使用[attribute$=value]選擇器對(duì)不同輪播圖使用同樣的樣式。而在代碼中也可以根據(jù)其容器id來(lái)區(qū)分不同輪播圖中的類似元素。因?yàn)橐С州啿D寬度自適應(yīng),所以采用來(lái)百分比設(shè)置后代元素寬度。

init: function(urlArr) {                //創(chuàng)建dom結(jié)構(gòu)
    this.wrap.style.position = "relative";
    this.wrap.style.overflow = "hidden";
    this.wrap.innerHTML = '<span id="' + this.wrapId + '_pre" class="fa fa-angle-left fa-3x"></span><span id="' + this.wrapId + '_next" class="fa fa-angle-right fa-3x"></span><ul id="' + this.wrapId + '_page"></ul><div id="' + this.wrapId + '_container"></div>';
    let container = document.getElementById(this.wrapId + '_container');
    let page = document.getElementById(this.wrapId + "_page");
    for (let value of urlArr) {         //構(gòu)建圓點(diǎn)
        container.innerHTML += '<div class="' + this.wrapId + '_img-item">![](' + value + ')</div>';
        page.innerHTML += '<li class="' + this.wrapId + '_pagination"></li>';
    }
    container.style.width = this.imgNumber + "00%";
    container.style.left = 0;
    for (let value of document.getElementsByClassName(this.wrapId + "_img-item")) {
        value.style.width = 100 / this.imgNumber + "%";
    }
    document.getElementsByClassName(this.wrapId + "_pagination")[this.activePage].id = this.wrapId + "_active";        
    this.pageActiveColor();
    this.setTime();
    this.bindEvent();
}

創(chuàng)建的結(jié)構(gòu)大體上如圖下所示:#id代表用戶定義的容器,生成一個(gè)#(id)_container的包裹元素,寬度是容器寬度的圖片張數(shù)倍,.(id)_img-item[n]的寬度和高度都等同于容器,圖片在各自的.(id)_img-item[n]里鋪滿。給容器定義屬性position: relative,通過(guò)設(shè)置了絕對(duì)定位的#(id)_containerleft值來(lái)實(shí)現(xiàn)輪播。

輪播圖結(jié)構(gòu).png

為左右箭頭以及下邊的小圓點(diǎn)添加事件,在鼠標(biāo)移入輪播圖時(shí)停止自動(dòng)播放,移出時(shí)設(shè)置自動(dòng)播放。需要注意的是addEventListener的第二個(gè)參數(shù)必須是bindthis后的函數(shù)。因?yàn)檎{(diào)用環(huán)境自帶的函數(shù)會(huì)使this的綁定丟失,如果不清楚this的指向的話可以看這篇文章

bindEvent: function() {                 //綁定事件
    let preAngle = document.getElementById(this.wrapId + "_pre");
    let nextAngle = document.getElementById(this.wrapId + "_next");
    let pageUl = document.getElementById(this.wrapId + "_page");
    let pages = pageUl.getElementsByClassName(this.wrapId + "_pagination");
    for (let key = 0; key < pages.length; key++) {
        pages[key].addEventListener("click", this.selectPage.bind(this, key));
        console.log(key);
    }
    this.wrap.addEventListener("mouseenter", this.clearTime.bind(this));
    this.wrap.addEventListener("mouseleave", this.setTime.bind(this));
    preAngle.addEventListener("click", this.leftAngleclick.bind(this));
    nextAngle.addEventListener("click", this.rightAngleclick.bind(this));
}

切換圖片的基本思路就是改變實(shí)例屬性中的當(dāng)前頁(yè)這個(gè)變量,然后根據(jù)這個(gè)變量的值對(duì)包裹元素進(jìn)行定位,再使對(duì)應(yīng)的小圓點(diǎn)變色。下邊是點(diǎn)擊左箭頭觸發(fā)的函數(shù),判斷如果處于邊緣就跳到最后。點(diǎn)擊右箭頭和下邊圓點(diǎn)的事件與之類似。

leftAngleclick: function() {            //點(diǎn)擊左箭頭
        let container = document.getElementById(this.wrapId + "_container");
        if(this.activePage == 0) {      //判斷是否到邊緣
            this.activePage = this.imgNumber - 1;
        } else {
            this.activePage--;
        }
        container.style.left = "-" + this.activePage + "00%";
        this.pageActiveColor();
    }

最后給輪播圖添加自動(dòng)播放功能,即利用定時(shí)器每3秒觸發(fā)一次右箭頭的點(diǎn)擊事件。將返回的定時(shí)器保存到實(shí)例屬性中,以便在鼠標(biāo)懸停的時(shí)候停止自動(dòng)輪播。

setTime: function() {                           //自動(dòng)播放
        let wrapId = this.wrapId;               //解決this綁定丟失
        this.settimeID = setInterval(function() {
            document.getElementById(wrapId + "_next").click();
        } , 3000);
        console.log("set");
    },
clearTime: function() {                         //鼠標(biāo)懸浮取消自動(dòng)播放
        let theId = this.settimeID;             //解決this綁定丟失
        console.log("clear");
        clearInterval(theId);        
    }

到這輪播圖組件就算寫好了,這可以讓我們少寫很多代碼,而且可以在一個(gè)頁(yè)面中多次使用,不會(huì)污染到全局變量。缺陷在于這時(shí)的輪播圖還不能支持10張以上的圖片,因?yàn)榭紤]到這種需求并不是很多,就沒(méi)有寫10張以上的判斷條件,有需要時(shí)可以自行添加。可以點(diǎn)擊這里預(yù)覽最終效果,如果對(duì)于這篇博客有什么建議或想法,歡迎到博客下方留言。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,143評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 175,553評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 62,620評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,416評(píng)論 6 405
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 54,940評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 42,170評(píng)論 0 287
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,709評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,597評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,784評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評(píng)論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,029評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 34,407評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 35,663評(píng)論 1 280
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,403評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,746評(píng)論 2 370

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,597評(píng)論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,147評(píng)論 4 61
  • 通過(guò)學(xué)習(xí),我理解了圖片輪播原理,學(xué)習(xí)了setTimeout()、setInterval()函數(shù)設(shè)置定時(shí)器與清除定時(shí)...
    McRay閱讀 2,178評(píng)論 0 7
  • 主要思路 1.我們需要自定義一個(gè)繼承自FrameLayout的布局,利用FrameLayout布-局的特性(在同一...
    ZebraWei閱讀 2,303評(píng)論 0 5
  • 2008年,地震,中考,遇見(jiàn)你。 該怎么去形容那一年呢,5月的地震,麗麗把呆若木雞的我從搖搖晃晃的教學(xué)樓里面拉出來(lái)...
    小灣仔仔閱讀 282評(píng)論 0 1