閱讀994 返回首頁    go 阿裏雲 go 技術社區[雲棲]


jquery插件的編寫

jquery有著成千上萬的第三方插件,有時我們寫好了一個獨立的功能,也想將其與jquery結合起來,可以用jquery鏈式調用,這就要擴展jquery,寫成插件形式了,如下麵就是一個簡單擴展Jquery對象的demo:

(function ($) {   //sample:擴展jquery對象的方法,bold()用於加粗字體
  $.fn.extend({
    "bold": function () {
      ///<summary> 加粗字體</summary>
      return this.css({ fontWeight: "bold" });
    }
  });
})(jQuery);

這是一個非常簡單的擴展。接下來我們一步步來解析上麵的代碼

容器:一個即時執行函數

根本上來說,每個插件的代碼是被包含在一個即時執行的函數當中

(function(arg1, arg2) {
   // 代碼
})(arg1, arg2);

即時執行函數,顧名思義,是一個函數。讓它與眾不同的是,它被包含在一對小括號裏麵,這讓所有的代碼都在匿名函數的局部作用域中運行。這並不是說DOM(全局變量)在函數內是被屏蔽的,而是外部無法訪問到函數內部的公共變量和對象命名空間。這是一個很好的開始,這樣你聲明你的變量和對象的時候,就不用擔心變量名和已經存在的代碼有衝突

因為函數內部所有公共變量是無法訪問的,這樣要把jQuery本身作為一個內部的公共變量來使用就會成為問題。就像普通的函數一樣,即時函數也根據引用傳入對象參數。我們可以將jQuery對象傳入函數

(function($) { 
   // 局部作用域中使用$來引用jQuery
})(jQuery);

我們把公共變量“jQuery”傳入了一個即時執行的函數裏麵,在函數局部(容器)中我們可以通過“$”來引用它。也就是說,我們把容器當做一個函數來調用,而這個函數的參數就是jQuery。因為我們引用的“jQuery”作為公共變量傳入,而不是它的簡寫“$”,這樣我們就可以兼容Prototype庫。如果你不用Prototype或者其它用“$”做簡寫的庫的話,你不這樣做也不會造成什麼影響,但是知道這種用法仍是一件好事

插件:一個函數

一個jQuery插件本質上是我們塞進jQuery命名空間中一個龐大的函數,當然,我們可以很輕易地用jQuery.pluginName=function來達到我們的目的,但是如果我們這樣做的話我們的插件的代碼是處於沒有被保護的暴露狀態的。“jQuery.fn”是“jQuery.prototype”的簡寫,意味當我們通過jQuery命名空間去獲取我們的插件的時候,它僅可寫(不可修改)。它事實上可以為你幹點什麼事呢?它讓你恰當地組織自己的代碼,理解如何保護你的代碼不受運行時候不需要的修改。最好的說法就是,這是一個很好的實踐

通過一個插件,我們獲得一個基本的jQuery函數:

(function($) {
    $.fn.pluginName = function(options) {
        return this;
    } 
})(jQuery);   // 代碼在此處運行

上麵代碼中的函數可以像其他的jQuery函數那樣通過“$(‘#element’).pluginName()”來調用。注意是如何把“return this”語句加進去的;這小片的代碼通過返回一個原來元素集合(包含在this當中)的引用來產生鏈式調用的效果,而這些元素是被一個jQuery對象所包裹的。也應該注意,“this”在這個特定的作用域中是一個jQuery對象,相當於“$(‘#element’)”

根據返回的對象,我們可以總結出,在上麵的代碼中,使用“$(‘#element’).pluginName()”的效果和使用“$(‘#element’)”的效果是一樣的。在你的即時執行函數作用域中,沒必要用“$(this)”的方式來把this包裹到一個jQuery對象中,因為this本身已經是被包裝好的jQuery對象

多個元素:理解Sizzle

Query使用的選擇器引擎叫Sizzle,Sizzle可以為你的函數提供多元素操作(例如對所有類名相同的元素)。這是jQuery幾個優秀的特性之一,但這也是你在開發插件過程中需要考慮的事情。即使你不準備為你的插件提供多元素支持,但為這做準備仍然是一個很好的實踐

這裏添加一小段代碼,讓你的插件代碼為多元素集合中每個元素單獨地起作用:

function($) {
    $.fn.pluginName = function(options) {   // 向jQuery中被保護的“fn”命名空間中添加你的插件代碼,用“pluginName”作為插件的函數名稱
        return this.each(function() {   // 返回“this”(函數each()的返回值也是this),以便進行鏈式調用
            var $this = $(this);   // 此處運行代碼,可以通過“this”來獲得每個單獨的元素;例如: $(this).show(); 
        }); 
    } 
})(jQuery);

在以上示例代碼中,我並不是用 each()在我的選擇器中每個元素上運行代碼。在那個被 each()調用的函數的局部作用域中,你可以通過this來引用每個被單獨處理的元素,也就是說你可以通過$(this)來引用它的jQuery對象。在局部作用域中,我用$this變量存儲起jQuery對象,而不是每次調用函數的時候都使用$(this),這會是個很好的實踐。當然,這樣做並不總是必要的;但我已經額外把它包含在我的代碼中。還有要注意的是,我們將會對每個單獨方法都使用 each(),這樣到時我們就可以返回我們需要的值,而不是一個jQuery對象

假如我們的插件支持一個 val 的方法,它可以返回我們需要的值:

$('#element').pluginName('val');   // 會返回我們需要的值,而不是一個jQuery對象

功能:公有方法和私有方法

一個基本的函數可能在某些情況下可以良好地工作,但是一個稍微複雜一點的插件就需要提供各種各樣的方法和私有函數。你可能會使用不同的命名空間去為你的插件提供各種方法,但是最好不要讓你的源代碼因為多餘的命名空間而變得混亂

下麵的代碼定義了一個存儲公有方法的JSON對象,以及展示了如何使用插件中的主函數中去判斷哪些方法被調用,和如何在讓方法作用到選擇器每個元素上

(function($) {
    var privateFunction = function() {   // 在我們插件容器內,創造一個公共變量來構建一個私有方法
        // code here
    }
    var methods = {   // 通過字麵量創造一個對象,存儲我們需要的共有方法
        init: function() {   // 在字麵量對象中定義每個單獨的方法
            return this.each(function() {   // 為了更好的靈活性,對來自主函數,並進入每個方法中的選擇器其中的每個單獨的元素都執行代碼
                var $this = $(this);   // 為每個獨立的元素創建一個jQuery對象 
                // 執行代碼;例如: privateFunction();
            });
        },
        destroy: function() {
            return this.each(function() {   // 對選擇器每個元素都執行方法
                // 執行代碼
            });
        }
    }; 
    $.fn.pluginName = function() {
        var method = arguments[0];   // 獲取我們的方法,遺憾的是,如果我們用function(method){}來實現,這樣會毀掉一切的
        if(methods[method]) {   // 檢驗方法是否存在
            method = methods[method];   // 如果方法存在,存儲起來以便使用;注意:我這樣做是為了等下更方便地使用each()
        } else if( typeof(method) == 'object' || !method ) {   // 如果方法不存在,檢驗對象是否為一個對象(JSON對象)或者method方法沒有被傳入
            method = methods.init;   // 如果我們傳入的是一個對象參數,或者根本沒有參數,init方法會被調用
        } else {
            $.error( 'Method ' +  method + ' does not exist on jQuery.pluginName' );   // 如果方法不存在或者參數沒傳入,則報出錯誤。需要調用的方法沒有被正確調用
            return this;
        }       
        return method.call(this);   // 調用我們選中的方法;再一次注意我們是如何將each()從這裏轉移到每個單獨的方法上的 
    } 
})(jQuery);

注意我把 privateFunction 當做了一個函數內部的全局變量。考慮到所有的代碼的運行都是在插件容器內進行的,所以這種做法是可以被接受的,因為它隻在插件的作用域中可用。在插件中的主函數中,檢驗了傳入參數所指向的方法是否存在。如果方法不存在或者傳入的是參數為對象, init 方法會被運行。最後,如果傳入的參數不是一個對象而是一個不存在的方法,我們會報出一個錯誤信息

同樣要注意的是如何在每個方法中都使用 this.each() 。當我們在主函數中調用 method.call(this) 的時候,這裏的 this 事實上就是一個jQuery對象,作為 this 傳入每個方法中。所以在我們方法的即時作用域中,它已經是一個jQuery對象。隻有在被 each()所調用的函數中,我們才有必要將this包裝在一個jQuery對象中

JQuery自定義插件主要有兩個方法:

為了方便用戶創建插件,jquery提供了jQuery.extend()(類方法)和jQuery.fn.extend()(對象方法)兩種方法

這兩個方法都接受一個參數,類型為Object,Object對應的"名/值對"分別代表"函數或方法體/函數主體"

給JQuery類添加新方法

;(function($){  
    $.fn.extend({  
        "函數名":function(自定義參數){  
            //這裏寫插件所需要的代碼  
        }  
    });  
})(jQuery);  
或者  
;(function($){  
    $.fn.函數名=function(自定義參數){  
        //這裏寫插件所需要的代碼  
    }  
})(jQuery); 

使用以下方式調用添加的新方法:$("#id").函數名(參數);

相當於添加靜態方法

;(function($){  
    $.extend({  
        "函數名":function(自定義參數){  
            //這裏寫插件代碼  
        }  
    });  
})(jQuery);  
或者  
;(function($){  
    $.函數名=function(自定義參數){  
        //這裏寫插件代碼  
    }  
})(jQuery);  

使用以下方式調用添加的新方法:$.函數名(參數);

最後更新:2017-06-14 18:01:54

  上一篇:go  市場排名第一的WAF,四大黑科技是怎樣煉成的?
  下一篇:go  MySQL鎖係列(五)之 隔離級別