2009-10-07 93 views
5

我試圖創建一個jQuery插件,將創造這樣一個autoCompleteBox但自定義功能。如何爲每個匹配的jQuery元素存儲成員變量?如何有成員變量和公共方法的jQuery插件?

比如我需要存儲的timerId每個。我還想存儲對構成控件的一些DOM元素的引用。

我希望能夠做出的作品像一個公共方法:

$("#myCtrl").autoCompleteEx.addItem("1"); 

不過的addItem()的執行我怎麼能訪問成員變量像它的timerId特定對象管他呢?

下面是我迄今爲止...

感謝任何幫助或建議!

(function($) 
{  
    //Attach this new method to jQuery 
    $.fn.autoCompleteEx = function(options) 
    {  
     //Merge Given Options W/ Defaults, But Don't Alter Either 
     var opts = $.extend({}, $.fn.autoCompleteEx.defaults, options); 


     //Iterate over the current set of matched elements 
     return this.each(function() 
     { 
      var acx = $(this); //Get JQuery Version Of Element (Should Be Div) 

      //Give Div Correct Class & Add <ul> w/ input item to it 
      acx.addClass("autoCompleteEx"); 
      acx.html("<ul><li class=\"input\"><input type=\"text\"/></li></ul>"); 

      //Grab Input As JQ Object 
      var input = $("input", acx); 

      //Wireup Div 
      acx.click(function() 
      { 
       input.focus().val(input.val()); 
      }); 


      //Wireup Input 
      input.keydown(function(e) 
      { 
       var kc = e.keyCode; 
       if(kc == 13) //Enter 
       { 

       } 
       else if(kc == 27) //Esc 
       { 

       } 
       else 
       { 
        //Resize TextArea To Input 
        var width = 50 + (_txtArea.val().length*10); 
        _txtArea.css("width", width+"px");  
       } 
      }); 

     }); //End Each JQ Element 

    }; //End autoCompleteEx() 

    //Private Functions 
    function junk() 
    { 

    }; 

    //Public Functions 
    $.fn.autoCompleteEx.addItem = function(id,txt) 
    { 
     var x = this; 
     var y = 0; 
    }; 

    //Default Settings 
    $.fn.autoCompleteEx.defaults = 
    { 
     minChars: 2, 
     delay:  300, 
     maxItems: 1 
    }; 

    //End Of Closure 
})(jQuery); 

回答

7

我發現,處理這個jQuery UI的方式似乎摸出最好的。你創建你的「額外的方法」作爲一個字符串參數傳遞給你的插件:

$('#elem').autoCompleteEx('addItem', '1'); 

那麼「這個」背景下被保留,並且可以沿着這些路線做一些事情:

function addItem() { 
    // this should be == jquery object when this get called 
} 

$.fn.autoCompleteEx = function(options) { 
    if (options === 'addItem') { 
    return addItem.apply(this, Array.prototype.splice.call(arguments, 1)); 
    } 
}; 
+0

你是一個天才......感謝一百萬! – Legend 2010-06-01 03:06:31

1

看看jQuery的.data功能。它可讓您將鍵/值對存儲在任何對象上。

+0

是的,看起來像它可以工作了我。你知道這是我想要完成的首選方法嗎? – user169867 2009-10-07 20:13:18

+0

它的一個缺點是數據不是私有的。 – user169867 2009-10-07 20:13:54

1

使用這樣的事情:

acx.data("acx-somename", datavalue); 

然後,您可以稍後進行檢索:

var datavalue = acx.data("acx-somename"); 
+0

由於數據由存儲與所討論的DOM對象相關的數據的所有人共享,因此「acx-」前綴作爲名稱空間存在。 – 2009-10-07 20:16:39

+0

我明白了。謝謝安東尼和科裏。 – user169867 2009-10-07 20:18:51

4

這裏是我建立更復雜的插件插件時嘗試的模板:

(function($){ 

    // configuration, private helper functions and variables 
    var _defaultConfig = { 
     /* ... config ... */ 
     }, 
     _version = 1; 


    // the main controller constructor 
    $.myplugin = function (elm, config) { 

    // if this contructor wasn't newed, then new it... 
    if (this === window) { return new $.myplugin(elm, config || {}); } 

    // store the basics 
    this.item = $(elm); 
    this.config = new $.myplugin.config(config); 

    // don't rerun the plugin if it is already present 
    if (this.item.data('myplugin')) { return; } 

    // register this controlset with the element 
    this.item.data('myplugin', this); 

    // ... more init ... 

    }; 
    $.myplugin.version = _version; 
    $.myplugin.config = function (c) { $.extend(this, $.myplugin.config, c); }; 
    $.myplugin.config.prototype = _defaultConfig; 
    $.myplugin.prototype = { 

    /* ... "public" methods ... */ 

    }; 

    // expose as a selector plugin 
    $.fn.myplugin = function (config) { 
    return this.each(function(){ 
     new $.myplugin(this, config); 
    }); 
    }; 

})(jQuery); 

我把默認的配置和版本在頂部,只是因爲它最有可能的 閱讀代碼的任何人都在尋找。大多數時候,你只是想檢查 的設置阻止。

這將在兩個地揭露「爲myplugin」,作爲widget的 上$並作爲$.fn的收集方法「控制器」的構造函數。正如你所看到$.fn方法並沒有真正做除了實例化新的控制器東西。

該配置是一個原型繼承的對象,其中默認是原型。這可以極大地提高靈活性,可以讓 將「下一個」默認值分配爲$.myplugin.config,或者使用$.myplugin.config.prototype更改每個正在運行的插件的默認值。這確實需要你使用$ .extend分配到這些地址,否則你會破壞系統。更多的代碼可以抵消這一點,但我更願意知道我在做什麼。 :-)

控制器的實例通過jQuery的data()方法將自身綁定到元素,並且實際上用它來測試它不會在同一元素上運行兩次(儘管您可能想要允許重新配置它)。

這爲您提供以下接口控制器:

// init: 
$('div#myid').myplugin(); 

// call extraMethod on the controller: 
$('div#myid').data('myplugin').extraMethod(); 

這種方法最大的弊端是,它是一個有點疼痛,保持「本」與每一個事件任務的上下文。在事件的上下文到達jQuery之前,這需要用大量的閉包來完成。

這裏的(不完整的和無用的)插件會如何看一個粗略的例子:

(function($){ 

    // configuration, private helper functions and variables 
    var _defaultConfig = { 
     openOnHover: true, 
     closeButton: '<a href="#">Close</a>', 
     popup: '<div class="wrapper"></div>' 
     }, 
     _version = 1; 

    // the main controller constructor 
    $.myplugin = function (elm, config) { 

    // if this contructor wasn't newed, then new it... 
    if (this === window) { return new $.myplugin(elm, config || {}); } 
    this.item = $(elm); 
    this.config = new $.myplugin.config(config); 
    if (this.item.data('myplugin')) { return; } 
    this.item.data('myplugin', this); 

    // register some events 
    var ev = 'click' + (this.config.openOnHover) ? ' hover' : ''; 
    this.item.bind(ev, function (e) { 
     $(this).data('myplugin').openPopup(); 
    }); 

    }; 
    $.myplugin.version = _version; 
    $.myplugin.config = function (c) { $.extend(this, $.myplugin.config, c); }; 
    $.myplugin.config.prototype = _defaultConfig; 
    $.myplugin.prototype = { 

    openPopup: function() { 
     var C = this.config; 
     this.pop = $(C.popup).insertAfter(this.item); 
     this.pop.text('This says nothing'); 
     var self = this; 
     $(C.closeButton) 
      .appendTo(pop) 
      .bind('click', function() { 
      self.closePopup(); // closure keeps context 
      return false; 
      }); 
     return this; // chaining 
    }, 

    closePopup: function() { 
     this.pop.remove(); 
     this.pop = null; 
     return this; // chaining 
    } 

    }; 

    // expose as a selector plugin 
    $.fn.myplugin = function (config) { 
    return this.each(function(){ 
     new $.myplugin(this, config); 
    }); 
    }; 

})(jQuery); 
0

實例操作!這就是你想要的,對吧?良好的舊時尚,實時操作。這也是我想要的。我搜索了同樣的問題,無法在任何地方得到很好的答案(比如上面的問題),所以我找到了答案。我不喜歡我的解決方案,因爲它看起來像獲得實例方法的一種方式,對於jQuery使用者來說很陌生,但jQuery在第一個位置很怪異,但很可愛。我寫了一個簡單的插件褪色的圖像,但再一次,我需要用它做更多,我想揭露的方法來現場實例在這裏得到這樣的結果 - >example,我做了以下內容:

var instanceAccessor = {}; 
var pluginOptions = {'accessor':instanceAccessor} 
$('div').myPlugin(pluginOptions); 

然後在插件內部,我添加了對象'accessor'傳入的方法,因爲它的對象。我揭露插件裏面的方法是這樣的:

if (pluginOptions.accessor != null && typeof(pluginOptions.accessor) === 'object') { 
    pluginOptions.accessor.exposedMethod = function (someParam) { 
    // call some private function here and access private data here 
    }; 
} 

然後,這個插件的用戶可以調用實例方法或方法的任何時間運行時就像我們使用的jQuery做這個陌生前做:

instanceAccessor.exposedMethod('somevalue'); 

你可以在jquery插件搜索中尋找「啞交叉淡入淡出」來找到我的愚蠢插件併爲自己查看代碼。

1

這裏有一個關於它我採取:

我有一個用來創建實例對象的閉包內的對象。實例對象使用jQuery的data()方法附加到元素節點。這些實例對象具有公共方法,您可以根據需要調用它們。

(function($) 
{  
// This is used to create AutoComplete object that are attatched to each element that is matched 
// when the plugin is invoked 
var AutoCompleteEx = function(options, acx) { 

    // PRIVATE VARIABLES 
    var timerID; 
    var input; 

    //Give Div Correct Class & Add <ul> w/ input item to it 
    acx.addClass("autoCompleteEx"); 
    acx.html("<ul><li class=\"input\"><input type=\"text\"/></li></ul>"); 

    //Grab Input As JQ Object 
    input = $("input", acx); 

    //Wireup Div 
    acx.click(function() 
    { 
     input.focus().val(input.val()); 
    }); 


    //Wireup Input 
    input.keydown(function(e) 
    { 
     var kc = e.keyCode; 
     if(kc == 13) //Enter 
     { 

     } 
     else if(kc == 27) //Esc 
     { 

     } 
     else 
     { 
      //Resize TextArea To Input 
      var width = 50 + (_txtArea.val().length*10); 
      _txtArea.css("width", width+"px");  
     } 
    }); 

    // PUBLIC METHODS 

    this.setTimerID = function(id) { 
    timerID = id; 
    }; 

    this.getTimerID = function() { 
    return timerID; 
    }; 

}; 


//Attach this new method to jQuery 
$.fn.autoCompleteEx = function(options) 
{  
    //Merge Given Options W/ Defaults, But Don't Alter Either 
    var opts = $.extend({}, $.fn.autoCompleteEx.defaults, options); 

    //Iterate over the current set of matched elements 
    return this.each(function() 
    { 
     var acx = $(this); //Get JQuery Version Of Element (Should Be Div) 

     // creating a new AutoCompleteEx object and attach to the element's data, if not already attached 
     if (!acx.data('autoCompleteEx')) { 
      acx.data('autoCompleteEx', new AutoCompleteEx(options, acx)); 
     } 

    }); //End Each JQ Element 

}; //End autoCompleteEx() 

//Default Settings 
$.fn.autoCompleteEx.defaults = 
{ 
    minChars: 2, 
    delay:  300, 
    maxItems: 1 
}; 

//End Of Closure 
})(jQuery); 

你可以這樣調用方法:

$("div#someDiv").autoCompleteEx(); 
$("div#someDiv").data('autoCompleteEx').setTimerID(123); 
var timerId = $("div").data('autoCompleteEx').getTimerID(); 
console.log(timerId); // outputs '123' 

如果你是實例化一個以上:

$("div.someDiv").autoCompleteEx(); 
$("div.someDiv").eq(0).data('autoCompleteEx').setTimerID(123); 
$("div.someDiv").eq(1).data('autoCompleteEx').setTimerID(124); 
var firstTimerId = $("div").eq(0).data('autoCompleteEx').getTimerID(); 
var secondTimerId = $("div").eq(1).data('autoCompleteEx').getTimerID(); 
console.log(firstTimerId); // outputs '123' 
console.log(secondTimerId); // outputs '124'