jQuery輪播圖(二)利用構造函數和原型創建對象以實現繼承


本文是在我開始學習JavaScript繼承時,對原型繼承的一些理解和運用。文中所述的繼承方式均是使用js特有的原型鏈方式,實際上有了ES6的類之后,實現繼承的就變得十分簡單了,所以這種寫法現在也不在推薦使用了,對於對象的繼承更推薦使用ES6的class來實現。我會在后續的文章中詳細介紹這種實現繼承的方式,歡迎關注。

2017年6月24日更新

------------------------------------------------------------------------------------------

以下為原文:

 

上一篇文中完成的封裝,還存在一個小問題,就是該輪播對象不能在同一頁面中重復使用,本文將通過組合使用javascript的構造函數和原型模式創建對象來解決這個問題。

沒有看過上一篇文章的朋友可以點此查看上一篇文章 (jQuery圖片輪播(一)輪播實現並封裝)

首先回顧一下,上文的問題所在,上文中的carsouel對象是采用字面量的方式來定義的,這樣carsouel本就是一個實例,想要使用在多處時,這個對象的方法會發生沖突,最終只會執行最后的那一個。而通過采用構造函數的方式來定義對象carsouel,每次需要使用時只需要用new操作符來實例化一個新對象,頁面中需要幾處輪播就實例化幾個對象,這樣就可以滿足需求。所以,將代碼改成以下形式。

function Carousel(){
    this.now = 0;                    //當前顯示的圖片索引
    this.hasStarted = false;         //是否開始輪播
    this.interval = null;            //定時器
    this.liItems = null;             //要輪播的li元素集合
    this.len = 0;                  //liItems的長度
    this.aBox : null;                //包含指示器的dom對象
    this.bBox : null;                //包含前后按鈕的dom對象

    /**
     * 初始化及控制函數
     * @param bannnerBox string 包含整個輪播圖盒子的id或class
     * @param aBox  string 包含指示器的盒子的id或class
     * @param btnBox string 包含前后按鈕的盒子的id或class
     */
    this.startPlay = function(bannnerBox,aBox,btnBox) {
        //初始化對象參數
        var that = this;
        this.liItems = $(bannnerBox).find('ul').find('li');
        this.len = this.liItems.length;
        this.aBox = $(bannnerBox).find(aBox);
        this.bBox = $(bannnerBox).find(btnBox);
        //讓第一張圖片顯示,根據輪播圖數量動態創建指示器,並讓第一個指示器處於激活狀態,隱藏前后按鈕
        this.liItems.first('li').css({'opacity': 1, 'z-index': 1}).siblings('li').css({'opacity': 0, 'z-index': 0});
        var aDom = '';
        for (var i = 0; i < this.len; i++){
            aDom += '<a></a>';
        }
        $(aDom).appendTo(this.aBox);
        this.aBox.find('a:first').addClass("indicator-active");
        this.bBox.hide();
        //鼠標移入banner圖時,停止輪播並顯示前后按鈕,移出時開始輪播並隱藏前后按鈕
        $(bannnerBox).hover(function (){
            that.stop();
            that.bBox.fadeIn(200);
        }, function (){
            that.start();
            that.bBox.fadeOut(200);
        });
        //鼠標移入指示器時,顯示對應圖片,移出時繼續播放
        this.aBox.find('a').hover(function (){
            that.stop();
            var out = that.aBox.find('a').filter('.indicator-active').index();
            that.now = $(this).index();
            if(out!=that.now) {
                that.play(out, that.now)
            }
        }, function (){
            that.start();
        });
        //點擊左右按鈕時顯示上一張或下一張
        $(btnBox).find('a:first').click(function(){that.next()});
        $(btnBox).find('a:last').click(function(){that.prev()});
        //開始輪播
        this.start()
    };
    //前一張函數
    this.prev = function (){
        var out = this.now;
        this.now = (--this.now + this.len) % this.len;
        this.play(out, this.now);
    };
    //后一張函數
    this.next = function (){
        var out = this.now;
        this.now = ++this.now % this.len;
        this.play(out, this.now);
    };
    /**
     * 播放函數
     * @param out number 要消失的圖片的索引值
     * @param now number 接下來要輪播的圖的索引值
     */
    this.play = function (out, now){
        this.liItems.eq(out).stop().animate({opacity:0,'z-index':0},500).end().eq(now).stop().animate({opacity:1,'z-index':1},500);
        this.aBox.find('a').removeClass('indicator-active').eq(now).addClass('indicator-active');
    };
    //開始函數
    this.start = function(){
        if(!this.hasStarted) {
            this.hasStarted = true;
            var that = this;
            this.interval = setInterval(function(){
                that.next();
            },2000);
        }
    };
    //停止函數
    this.stop = function (){
        clearInterval(this.interval);
        this.hasStarted = false;
    }
};

調用時采用new操作符,如下:

    var banner1 = new Carousel();
    var banner2 = new Carousel();
    var banner3 = new carousel();
    banner1.startPlay('#J_bg_ban1','#J_bg_indicator1','#J_bg_btn1');
    banner2.startPlay('#J_bg_ban2','#J_bg_indicator2','#J_bg_btn2');
    banner3.startPlay('#J_bg_ban3','#J_bg_indicator3','#J_bg_btn3');

上述方法可實現需求,但是仔細分析發現,這與上一篇文中使用extend復制對象的方法幾乎是一樣的,這里的new操作符實際上也是將構造函數完全復制了一份出來作為一個新的對象,那就和上文中提到的方法存在共同的缺點,那就是內部函數不能復用,每次執行用new操作符來實例化,都會創建新的內部函數,這也是單獨使用構造函數來自定義對象的缺點。

在Carousel對象內的play方法、next方法、prev方法、strat方法、stop方法其實都是可以共用的,多個輪播件共用這些函數是完全沒有問題的,而初始化方法需要在每個實例上單獨創建。單獨使用構造函數創建對象,在使用new操作符創建新實例的時候,初始化方法會被重新在每個實例上創建一遍,這正是我們想要的結果,而play方法、next方法、prev方法、start方法、stop方法這些可共用的方法也會在新實例上被重新創建,而創造多個完成一樣任務的方法是完全沒有必要的,所以需要將這些共有的方法提出來,讓所有Carousel對象的實例都可以公用,這樣就可以解決函數復用的問題。

通過將這些共用的方法寫在Carousel的原型對象上,在創建Carousel新實例的時候就可以通過原型鏈來共享這些方法,這樣這些公用函數也就得到了復用,代碼如下:

 

   // 構造函數加原型形式

    /**
     * 構造函數初始化及開始輪播
     * @param bannnerBox string 包含整個輪播圖盒子的id或class
     * @param aBox  string 包含指示器的盒子的id或class
     * @param btnBox string 包含前后按鈕的盒子的id或class
     */
    function Carousel(bannnerBox, aBox, btnBox) {
        this.now = 0; //當前顯示的圖片索引
        this.hasStarted = false; //是否開始輪播
        this.interval = null; //定時器
        this.liItems = null; //要輪播的li元素集合
        this.len = 0; //liItems的長度
        this.aBox = null; //包含指示器的dom對象
        this.bBox = null; //包含前后按鈕的dom對象

        //初始化函數
        this.init = function () {
            //初始化對象參數
            var that = this;
            this.liItems = $(bannnerBox).find('ul').find('li');
            this.len = this.liItems.length;
            this.aBox = $(bannnerBox).find(aBox);
            this.bBox = $(bannnerBox).find(btnBox);
            //讓第一張圖片顯示,根據輪播圖數量動態創建指示器,並讓第一個指示器處於激活狀態,隱藏前后按鈕
            this.liItems.first('li').css({
                'opacity': 1,
                'z-index': 1
            }).siblings('li').css({
                'opacity': 0,
                'z-index': 0
            });
            var aDom = '';
            for (var i = 0; i < this.len; i++) {
                aDom += '<a></a>';
            }
            $(aDom).appendTo(this.aBox);
            this.aBox.find('a:first').addClass("indicator-active");
            this.bBox.hide();
            //鼠標移入banner圖時,停止輪播並顯示前后按鈕,移出時開始輪播並隱藏前后按鈕
            $(bannnerBox).hover(function () {
                that.stop();
                that.bBox.fadeIn(200);
            }, function () {
                that.start();
                that.bBox.fadeOut(200);
            });
            //鼠標移入指示器時,顯示對應圖片,移出時繼續播放
            this.aBox.find('a').hover(function () {
                that.stop();
                var out = that.aBox.find('a').filter('.indicator-active').index();
                that.now = $(this).index();
                if (out != that.now) {
                    that.play(out, that.now)
                }
            }, function () {
                that.start();
            });
            //點擊左右按鈕時顯示上一張或下一張
            $(btnBox).find('a:first').click(function () {
                that.next()
            });
            $(btnBox).find('a:last').click(function () {
                that.prev()
            });
        }
        //初始化
        this.init();
        //開始輪播
        this.start();
    }


    /**
     * 播放函數
     * @param out number 要消失的圖片的索引值
     * @param now number 接下來要輪播的圖的索引值
     */
    Carousel.prototype.play = function (out, now) {
        this.liItems.eq(out).stop().animate({
            opacity: 0,
            'z-index': 0
        }, 500).end().eq(now).stop().animate({
            opacity: 1,
            'z-index': 1
        }, 500);
        this.aBox.find('a').removeClass('indicator-active').eq(now).addClass('indicator-active');
    }

    //前一張函數
    Carousel.prototype.prev = function () {
        var out = this.now;
        this.now = (--this.now + this.len) % this.len;
        this.play(out, this.now)
    }

    //后一張函數
    Carousel.prototype.next = function () {
        var out = this.now;
        this.now = ++this.now % this.len;
        this.play(out, this.now);
    }

    //開始函數
    Carousel.prototype.start = function () {
        if (!this.hasStarted) {
            this.hasStarted = true;
            var that = this;
            this.interval = setInterval(function () {
                that.next();
            }, 2000);
        }
    }
    //停止函數
    Carousel.prototype.stop = function () {
        clearInterval(this.interval);
        this.hasStarted = false;
    }

    $(function () {
        var banner1 = new Carousel('#J_bg_ban1', '#J_bg_indicator1', '#J_bg_btn1');
        var banner2 = new Carousel('#J_bg_ban2', '#J_bg_indicator2', '#J_bg_btn2');
    });

 

在這里對Carousel對象的原型對象進行了擴展,將play方法、next方法,perv方法,start方法和stop方法寫進了Carousel的原型對象中,這樣每次實例化的對象就可以共用這些方法。當然,實例化的方法也是使用new操作符。這樣我們就可以在同一頁面內多次使用這個輪播對象了。

這種組合使用構造函數和原型的模式,是創建自定義類型最常用的方法,至此我們就完成了這個簡單輪播對象的封裝。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM