1. 程式人生 > >jquery外掛封裝

jquery外掛封裝

擴充套件外掛和方法的作用是非常強大的,它可以節省大量開發時間。這篇文章將概述外掛開發的基本知識,最佳做法和常見的陷阱。

入門

編寫一個jQuery外掛開始於給jQuery.fn加入​​新的功能屬性,此處新增的物件屬性的名稱就是你外掛的名稱:

jQuery.fn.myPlugin = function(){

  //你自己的外掛程式碼

};

使用者非常喜歡的$符號哪裡去了? 它仍然存在,但是,為了避免和其他庫衝突,我們最好將jQuery傳遞給一個自我執行的封閉程式,jQuery在此程式中對映為$符號,這樣可以避免$號被其他庫覆寫。

(function ($) {
    $.fn.m​​yPlugin = function
()
{ //你自己的外掛程式碼 }; })(jQuery);

在這個封閉程式中,我們可以無限制的使用$符號來表示jQuery函式。

環境

現在,我們可以開始編寫實際的外掛程式碼。 但是,在這之前,我們必須得對外掛所處的環境有個概念。 在外掛的範圍裡, this關鍵字代表了這個外掛將要執行的jQuery物件, 這裡容易產生一個普遍的誤區,因為在其他包含callback的jQuery函式中,this關鍵字代表了原生的DOM元素。這常常會導致開發者誤將this關鍵字無謂的包在jQuery中,如下所示。

(function ($) {
    $.fn.m​​yPlugin = function
()
{ //此處沒有必要將this包在$號中如$(this),因為this已經是一個jQuery物件。 //$(this)等同於 $($('#element')); this.fadeIn('normal', function () { //此處callback函式中this關鍵字代表一個DOM元素 }); }; })(jQuery); $('#element').myPlugin();

基礎知識

現在,我們理解了jQuery外掛的基礎知識,讓我們寫一個外掛,做一些事情。

(function
($)
{ $.fn.m​​axHeight = function () { var max = 0; this.each(function () { max = Math.max(max, $(this).height()); }); return max; }; })(jQuery); var tallest = $('div').maxHeight(); //返回高度最大的div元素的高度

這是一個簡單的外掛,利用.height()返回頁面中高度最大的div元素的高度。

維護Chainability

很多時候,一個外掛的意圖僅僅是以某種方式修改收集的元素,並把它們傳遞給鏈中的下一個方法。 這是jQuery的設計之美,是jQuery如此受歡迎的原因之一。 因此,要保持一個外掛的chainability,你必須確保你的外掛返回this關鍵字。

(function ($) {

    $.fn.lockDimensions = function (type) {

        return this.each(function () {

            var $this = $(this);

            if (!type || type == 'width') {
                $this.width($this.width());
            }

            if (!type || type == 'height') {
                $this.height($this.height());
            }

        });

    };
})(jQuery);

$('div').lockDimensions('width').CSS('color', 'red');

由於外掛返回this關鍵字,它保持了chainability,這樣jQuery收集的元素可以繼續被jQuery方法如.css控制。 因此,如果你的外掛不返回固有的價值,你應該總是在其作用範圍內返回this關鍵字。 此外,你可能會推斷出,傳遞給外掛的引數將會在外掛的作用範圍內被傳遞。 因此,在前面的例子,字串’width’變成了外掛的型別引數。

預設值和選項

對於比較複雜的和提供了許多選項可定製的的外掛,最好有一個當外掛被呼叫的時候可以被拓展的預設設定(通過使用$.extend)。 因此,相對於呼叫一個有大量引數的外掛,你可以呼叫一個物件引數,包含你了你想覆寫的設定。

(function ($) {

    $.fn.tooltip = function (options) {

        //建立一些預設值,拓展任何被提供的選項
        var settings = $.extend({
            'location': 'top',
            'background-color': 'blue'
        }, options);

        return this.each(function () {

            // Tooltip外掛程式碼

        });

    };
})(jQuery);

$('div').tooltip({
    'location': 'left'
});

在這個例子中,呼叫tooltip外掛時覆寫了預設設定中的location選項,background-color選項保持預設值,所以最終被呼叫的設定值為:

{
    'location': 'left',
    'background-color': 'blue'
}

這是一個很靈活的方式,提供一個高度可配置的外掛,而無需開發人員定義所有可用的選項。

名稱空間

正確名稱空間你的外掛是外掛開發的一個非常重要的一部分。 正確的名稱空間,可以保證你的外掛將有一個非常低的機會被其他外掛或同一頁上的其他程式碼覆蓋。 名稱空間也使得你的生活作為一個外掛開發人員更容易,因為它可以幫助你更好地跟蹤你的方法,事件和資料。

外掛方法

在任何情況下,一個單獨的外掛不應該在jQuery.fnjQuery.fn物件裡有多個名稱空間。

(function ($) {

    $.fn.tooltip = function (options) {
        // this
    };
    $.fn.tooltipShow = function () {
        // is
    };
    $.fn.tooltipHide = function () {
        // bad
    };
    $.fn.tooltipUpdate = function (content) {
        // !!!
    };

})(jQuery);

這是不被鼓勵的,因為它$.fn使$.fn名稱空間混亂。 為了解決這個問題,你應該收集物件文字中的所有外掛的方法,通過傳遞該方法的字串名稱給外掛以呼叫它們。

(function ($) {

    var methods = {
        init: function (options) {
            // this
        },
        show: function () {
            // is
        },
        hide: function () {
            // good
        },
        update: function (content) {
            // !!!
        }
    };

    $.fn.tooltip = function (method) {

        // 方法呼叫
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method' + method + 'does not exist on jQuery.tooltip');
        }

    };

})(jQuery);

//呼叫init方法
$('div').tooltip();

//呼叫init方法
$('div').tooltip({
    foo: 'bar'
});

// 呼叫hide方法
$('div').tooltip('hide');

//呼叫Update方法
$('div').tooltip('update', 'This is the new tooltip content!');

這種型別的外掛架構允許您封裝所有的方法在父包中,通過傳遞該方法的字串名稱和額外的此方法需要的引數來呼叫它們。 這種方法的封裝和架構型別是jQuery外掛社群的標準,它被無數的外掛在使用,包括jQueryUI中的外掛和widgets。

事件

一個鮮為人知bind方法的功能即允許繫結事件名稱空間。 如果你的外掛繫結一個事件,一個很好的做法是賦予此事件名稱空間。 通過這種方式,當你在解除繫結的時候不會干擾其他可能已經繫結的同一型別事件。 你可以通過追加名稱空間到你需要繫結的的事件通過 <namespace>

(function ($) {

    var methods = {
        init: function (options) {

            return this.each(function () {
                $(window).bind('resize.tooltip', methods.reposition);
            });

        },
        destroy: function () {

            return this.each(function () {
                $(window).unbind('.tooltip');
            })

        },
        reposition: function () {
            //...
        },
        show: function () {
            //...
        },
        hide: function () {
            //...
        },
        update: function (content) {
            //...
        }
    };

    $.fn.tooltip = function (method) {

        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method ' + method + ' does not exist on jQuery.tooltip');
        }
    };

})(jQuery);

$('#fun').tooltip();
//一段時間之後... ...
$('#fun').tooltip('destroy');

在這個例子中,當tooltip通過init方法初始化時,它將reposition方法繫結到resize事件並給reposition非那方法賦予名稱空間通過追加.tooltip。 稍後, 當開發人員需要銷燬tooltip的時候,我們可以同時解除其中reposition方法和resize事件的繫結,通過傳遞reposition的名稱空間給外掛。 這使我們能夠安全地解除事件的繫結並不會影響到此外掛之外的繫結。

資料

通常在外掛開發的時候,你可能需要記錄或者檢查你的外掛是否已經被初始化給了一個元素。 使用jQuery的data方法是一個很好的基於元素的記錄變數的途徑。儘管如此,相對於記錄大量的不同名字的分離的data, 使用一個單獨的物件儲存所有變數,並通過一個單獨的名稱空間讀取這個物件不失為一個更好的方法。

(function ($) {

    var methods = {
        init: function (options) {

            return this.each(function () {

                var $this = $(this),
                    data = $this.data('tooltip'),
                    tooltip = $('<div />', {
                        text: $this.attr('title')
                    });

                // If the plugin hasn't been initialized yet
                if (!data) {

                    /*
                     Do more setup stuff here
                     */

                    $(this).data('tooltip', {
                        target: $this,
                        tooltip: tooltip
                    });

                }
            });
        },
        destroy: function () {

            return this.each(function () {

                var $this = $(this),
                    data = $this.data('tooltip');

                // Namespacing FTW
                $(window).unbind('.tooltip');
                data.tooltip.remove();
                $this.removeData('tooltip');

            })

        },
        reposition: function () {
            // ...
        },
        show: function () {
            // ...
        },
        hide: function () {
            // ...
        },
        update: function (content) {
            // ...
        }
    };

    $.fn.tooltip = function (method) {

        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method ' + method + ' does not exist on jQuery.tooltip');
        }

    };

})(jQuery);

將資料通過名稱空間封裝在一個物件中,可以更容易的從一個集中的位置讀取所有外掛的屬性。

總結和最佳做法

編寫jQuery外掛允許你做出庫,將最有用的功能整合到可重用的程式碼,可以節省開發者的時間,使開發更高效。 開發jQuery外掛時,要牢記:

  • 始終包裹在一個封閉的外掛:
(function($) {
/* plugin goes here */
})(jQuery);
  • 不要冗餘包裹this關鍵字在外掛的功能範圍內
  • 除非外掛返回特定值,否則總是返回this關鍵字來維持chainability 。
  • 傳遞一個可拓展的預設物件引數而不是大量的引數給外掛。
  • 不要在一個外掛中多次命名不同方法。
  • 始終名稱空間的方法,事件和資料。