第二期:JQ外掛編寫入門(2)

thattoti發表於2017-03-16

第二期:JQ編寫入門(2)

在看過我們上期的技術文章之後,大家應該知道關於JQ外掛的大概形式了。如果大家還沒有看過我的上一期文章,可以點下面連結
第一期:JQ外掛編寫入門(1)

JQ外掛內部的形式


; (function ($, window, document, undefined) {

    /*這裡定義的是私有變數,外部是訪問不到的*/
    var pluginName = `yourPluginName`,

        defaults = {

            properties: `name`

        };

    /*這裡定義的是私有函式,供內部呼叫*/
    function Plugin(element, options) {

        this.element = element;

        this.defaults = $.extend({}, defaults, options);

        this._defaults = defaults;

        this._name = pluginName;

        this.init();

    }

    Plugin.prototype={

        init:function(){

            //code

        },

        otherFunc:function(){

            //code

        }

    };

    /*這裡使用了$.fn方法來擴充外掛函式,當然也可以使用$.extend(),或者widget factory來達到相同的效果*/
    $.fn.pluginName = function (options) {

        return this.each(function () {

            if (!$(this).data(`plugin_` + pluginName)) {

                $(this).data(`plugin_` + pluginName, new Plugin(this, options));

            }

        });

    };

})(jQuery, window, document);

函式區域性分析

  • 私有變數

 /*這裡定義的是私有變數,外部是訪問不到的*/
    var pluginName = `yourPluginName`,

        defaults = {

            title: `title`,
            
            msg: `01`

        };

這裡的寫法,大家可以學習一下。首先我們,只用了一次Var變數宣告,這樣的好處是,不需要多次進行宣告,每個變數定義後,用逗號隔開,最後再以一個分號結尾。其中我們把外掛名字pluginName存放在一個變數裡面,這樣的好處是,我們瀏覽這個函式的開頭,就直接知道這個外掛的呼叫函式名字,而不需要拉到底部的$.fn.pluginName去檢視。雖然直接在那兒命名一點錯也沒有。但是大家要知道,往往我們開發,是需要接手別人的專案,那麼當一個外掛,寫了幾百行的程式碼,如果沒有清晰的結構,當別人接手我們專案維護時候,會很耗精力。

然後我們又宣告瞭一個私有變數defaults,這個變數的作用是用來設定我們外掛的預設值。為什麼這個地方要使用物件來儲存我們的預設引數。我們都遇到過一個情況:

function Example(num,string){
    
}

我們常用的傳參是一個個往裡面傳,那麼這個時候我們是要注意引數的順序的,當我們引數很多時候,我們不得不頭疼地記住每一個引數的順序:

function Example(num,string,obj,date,reg){

}
var ex=new Example(num, , , ,reg);

這樣子穿引數,就很不方便。所以我們就把引數放到一個物件裡面,這樣子,我們又可以不用注意引數的順序,又可以讓程式碼結構更加清晰。我們傳引數,就直接寫物件的變數名字就好了。

var data={
    num:``,
    string:``,
    obj:``,
    date:``,
    reg:``
}

function Example(data){
    //
}
  • 私有方法

    /*這裡定義的是私有函式,供內部呼叫*/
    function Plugin(element, options) {

        this.element = element;

        this.defaults = $.extend({}, defaults, options);

        this._defaults = defaults;

        this._name = pluginName;

        this.init();

    }

    Plugin.prototype={

        init:function(){

            //code

        },

        otherFunc:function(){

            //code

        }

    };
    
    /*外掛程式碼後段的例項化
    *組合起來看
    * new Plugin(this, options)
    */
    

這裡我們用了設計模式,具體關於設計模式我們就不展開去講。首先我們定義了一個叫Plugin的function,我們在裡面用this定義靜態變數和方法。

  this.defaults = $.extend({}, defaults, options);

這段程式碼的意思的是,把傳入的引數(就是使用者的自定義引數)與我們的預設值(預設引數值)合併到一個物件裡面,同時不會修改defaults和options的值。

$.extend(defaults,options)

這樣子使用,那麼我們options的引數會合併到defaults裡面,defaults的預設值就被修改了。但很多時候,我們不希望defaults被修改,所以才用第一種方法。

$.extend(true/false,{},defaults,options)

這個方法的第一個引數是可選的,true代表深克隆,false代表淺克隆,就是true的時候,會遞迴到陣列或者物件深處去合併。通常這個方法用在陣列或者物件上,如果只是一般的資料型別,我們有一種很簡單的方法實現預設值和自定義值的選擇。

var newString = string || ``;

var newNum = num ? num : 123;

當我們不需要處理陣列或者物件時候,我們就可以用上面兩種寫法,第一種是有字串string時候取string,沒有則取字串為空;第二種是有數字num時候取num,沒有則取一個預設值數字123.

this.init();

初始化原型方法,當我們例項化這個函式時候,原型函式就執行

Plugin.prototype = {

    init: function () {
        //
    },

    otherFuc: function () {
        //
    }

}

這裡我們把函式的方法寫到原型裡面,當我們例項化的時候,就不需要每次new都把方法都複製一遍。所以,每個Plugin的例項,用的方法都是呼叫原型裡面的,這樣可以較好地提升效能。

  • JQ外掛擴充方法

    /*這裡使用了$.fn方法來擴充外掛函式,當然也可以使用$.extend(),或者widget factory來達到相同的效果*/
    $.fn.pluginName = function (options) {

        return this.each(function () {

            if (!$(this).data(`plugin_` + pluginName)) {

                $(this).data(`plugin_` + pluginName, new Plugin(this, options));

            }

        });

    };

終於到了我們外掛擴充的寫法了。當我們去看jq原始碼的時候,其實:

$.fn = $.prototype;

其實我們這種寫法就是在jQuery的原型去擴充一個方法。所以我們在平時使用的時候,就可以用$.pluginName的形式去呼叫方法。

return ...

為什麼這裡要return呢,因為當我們返回這個方法,我們可以對它鏈式呼叫。例如,$.pluginName1().pluginName2();

return this.each(function(){
    //
});

這裡的this,指的是$。在$.fn裡面,this是指向jQuery物件。但是在this.each(function(){})裡的this,指的是function的每層迴圈的上下文,如果要用jQuery物件,那麼就要用$

return this.each(function () {

    if (!$(this).data(`plugin_` + pluginName)) {

        $(this).data(`plugin_` + pluginName, new Plugin(this, options));

    }

});

在這個函式裡面,我們用if先判斷有沒有這個外掛方法,如果沒有,我們就new一個例項,然後資料儲存到這個外掛裡面。在這裡我們用到$.data()方法。這個方法簡單點說,就是資料快取到某個元素上面。當我們不帶引數的時候,我們就是讀取;帶引數,就是鍵值對的設定。

<p></p>

$("p").data(); //undefined
$("p").data("a","hello"); //a=="hello"
$("p").data("b",{first:1,second:"abc"}); 
$("p").data("b").first; //1

用法大概類似如此。

這期介紹了外掛的寫法,那麼下期,和大家分享一下自己寫的幾個外掛例項。

相關文章