如何在jQuery插件中拥有成员变量和公共方法?

时间:2009-10-07 19:56:56

标签: jquery

我正在尝试创建一个jQuery插件,它将创建类似autoCompleteBox但具有自定义功能的东西。如何为每个匹配的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); 

6 个答案:

答案 0 :(得分:7)

我发现jQuery UI处理这个问题的方法看起来效果最好。您可以创建“额外方法”作为插件的字符串参数:

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

然后保留'this'上下文,你可以按照这些方式做点什么:

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));
   }
};

答案 1 :(得分: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”,作为小部件“控制器”的构造函数 在$上,以及$.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);

答案 2 :(得分:1)

看看jQuery的.data功能。它允许您在任何对象上存储键/值对。

答案 3 :(得分:1)

使用类似的东西:

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

然后您可以使用以下方法检索它:

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

答案 4 :(得分: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'

答案 5 :(得分:0)

实例操作!这就是你想要的,对吧?好旧时尚,实时操作实例。这也是我想要的。我用Google搜索了同样的问题,无法在任何地方得到一个好的答案(如上面的那些),所以我想出来了。我不喜欢我的解决方案,因为它似乎是关于获取实例方法的一种方式而且对于jquery消费者来说很奇怪,但jQuery在第一时间却很奇怪但很可爱。我写了一个简单的插件来淡化图像但是一旦我需要用它做更多的事情,我想把方法公开给一个实例来获得这个结果 - &gt; 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插件搜索中查找“哑交叉淡入淡出”,找到我的哑插件并亲自查看代码。