2012-02-16 2 views
4

Я пишу свой первый плагин jQuery. Вот скелет плагина:Получение идентификатора элемента управления, к которому подключен мой плагин 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 

, потому что я получаю свой ID от this, который оценивает [] для любого элемента управления, которого нет на странице. Я сейчас на сайте!

Каков правильный способ получить идентификатор элементов управления, к которым подключен плагин?

Большое спасибо :).

+1

Действительно ли вы хотите 'id', или вы хотите, чтобы вся строка селектора? Что делать, если плагин был применен к набору элементов, у которых не было 'id'? –

ответ

11

Там фундаментальный вопрос здесь: Вы думаете об отдельном элементе. jQuery - все о наборах элементов. в вашем плагине - это экземпляр jQuery, который может содержать 0..n элементов. Может быть ноль, один, 27, 342 и т. Д. Таким образом, this[0].id на самом деле не имеет смысла в подключаемом модуле jQuery, потому что вы просто получите id первого совпадающего элемента (если он даже имеет один, нет требование, которое оно должно), или ошибка (как вы обнаружили), когда вообще нет элементов в наборе.

Итак, если вы начинаете думать о своем подключаемом модуле, имея в виду набор совпадающих элементов, которые могут быть пустым набором, небольшим набором или большим набором, вы будете на правильном пути.

Вот конкретный пример: давайте напишем плагин, который делает глупую вещь: он превращает элемент (ы) в цвет, а затем возвращает их к исходному цвету после таймаута. Мы будем использовать его как это:

$("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

+0

Блестящий ответ. Не только предоставил мне иллюстративное решение, но и переосмыслил основную часть моего плагина. Огромное спасибо. – ale

+0

@ яркие цвета: добро пожаловать! Рад, что помогло. –

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'); 
    } 
    }); 
}; 
Смежные вопросы