获取我的jQuery插件所附加的控件的ID

时间:2012-02-16 12:54:48

标签: jquery jquery-plugins

我正在编写我的第一个jQuery插件。这是插件的骨架:

(function( $ ) {
    var methods = {
        init : function( options ) { 
            var settings = $.extend( {
                'id' : '#' + this[0].id,
                'foo' : 3,       
                'bar' : 4,    
            }, options ); 
        }
   }

   $.fn.MyPlugin = 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 MyPlugin' );
      }
  };
})( jQuery );

我附上了这样的插件:

$( '#some-id' ).MyPlugin({
   'something' : 'something
});

在一个页面上适用于一个控件,但是当我开始这样做时:

$( '#some-id-2' ).MyPlugin({
   'something' : 'something
});

$( '#some-id-3' ).MyPlugin({
   'something' : 'something
});

我收到以下错误:

Uncaught TypeError: Cannot read property 'id' of undefined

因为我从this获取了我的ID,对于我目前所在页面上没有的任何控件,其评估结果为[]

获取插件附加控件的ID的正确方法是什么?

非常感谢:)。

2 个答案:

答案 0 :(得分:11)

这里有一个根本问题:你在思考一个单独的元素。 jQuery完全是关于 sets 的元素。插件中的this是一个jQuery实例,其中可能包含0..n个匹配的元素。可能是零,一,27,342等。所以做this[0].id在jQuery插件中没有意义,因为你只需得到第一个匹配元素的id(如果它甚至有一个;没有必要的要求),或者当集合中根本没有任何元素时出现错误(如你所发现的那样)。

因此,如果您开始考虑将插件视为处理匹配元素的 set ,这些元素可能是空集,小集或大集,那么您将会在正确的道路。

这是一个具体的例子:让我们编写一个做傻事的插件:它将元素变成一种颜色,然后在超时后将它们恢复为原始颜色。我们将这样使用它:

$("selector").plugin("newcolor", timeout)

如果我们考虑单个元素,我们的插件将无法正常工作:

// The "foo" plug-in thinks in terms of just one element
$.fn.foo = function(color, time) {
    var self, oldColor;

    self = this;

    // Save the current color -- this is wrong
    oldColor = self.css("color");

    // Set new color
    self.css("color", color);

    // Restore old color after timeout
    setTimeout(function() {
      self.css("color", oldColor);
    }, time);
};

现在让我们使用它:

$("#theButton").click(function() {
    $(".foo").foo("blue", 1000);
});

...使用此HTML:

<div class="foo">This is the first "foo" div</div>
<div class="foo" style="color: green">This is the second "foo" div</div>
<div class="foo" style="color: red">This is the third "foo" div</div>
<div><input type="button" id="theButton" value="Use foo"></div>

这里的问题是,通过考虑一个元素,插件错误地保存了第一个元素的颜色;当它“恢复”原始颜色时,它将第一个元素的颜色应用于所有其他颜色,这是错误的。我们最终得到三个使用黑色文本的div,其中第二个不应该是黑色。 Live example | Source

相反,如果我们按照集合来思考,我们会这样做(例如;不要说这是地球上最漂亮的代码):

// The "bar" plug-in understands sets
$.fn.bar = function(color, time) {
    var self;

    self = this;

    // Get the current color of each element
    self.each(function() {
      var entry = $(this);
      entry.data("oldColor", entry.css("color"));
    });

    // Set new color
    self.css("color", color);

    // Restore old color after timeout
    setTimeout(function() {
      self.each(function() {
        var entry = $(this);
        entry.css("color", entry.data("oldColor")).removeData("oldColor");
      });
    }, time);
};

我们会像这样使用它(基本相同):

$("#theButton").click(function() {
    $(".bar").bar("blue", 1000);
});

...使用此HTML(基本相同):

<div class="bar">This is the first "bar" div</div>
<div class="bar" style="color: green">This is the second "bar" div</div>
<div class="bar" style="color: red">This is the third "bar" div</div>
<div><input type="button" id="theButton" value="Use foo"></div>

请注意它是如何通过data保存每个元素的颜色以及元素本身的颜色。恢复时,它会恢复每个元素的颜色。 Live example | Source

答案 1 :(得分:1)

您应该使用each实现插件,然后您就不会遇到空jQuery对象的问题:

$.fn.MyPlugin = function( method ) {
  this.each(function() {
    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 MyPlugin' );
    }
  });
};