2015-07-17 2 views
2

Я создаю плагин JQuery для этого первого раза - почти там - и пытаюсь найти лучший «шаблонный» для удовлетворения нижеперечисленных потребностей.

Вот моя проблема:

See my JS Fiddle

Я не могу получить плагин для работы на элементах по их имени класса.

Это работает:

var myPlugin = $('#single').myPlugin(); // Yes - it gets initialised 
myPlugin.doAFunction(" Some Params "); // Yes - public access func works 

Это НЕ работы:

var myPluginFooClass = $('.foo').myPlugin(); // Yes, it gets initialised 
myPlugin.doAFunction(" Some Params ");  // NO - now this falls over 

Вот что мне нужно достичь:

  • Несколько экземпляров на том же страница
  • Каждый экземпляр имеет свои собственные переменные, которые не перезаписываются другими экземплярами при их развертывании (я использую $ .data)
  • Публичные функции доступа влияют только на этот экземпляр, а не на другие экземпляры!
  • экземпляры могут быть развернуты на одном элементе по его идентификатору (#myElement)
  • экземпляры могут быть развернуты на элементах по классам (.foo) - это то, что не работает

Вот мой Jquery код:

(function($){ 

$.fn.myPlugin = function(options) { 
    // support multiple elements 
    if (this.length > 1){ 
     this.each(function() { $(this).myPlugin(options) }); 
     return this; 
    } 

    // -- private variables -- 
    var $this = $(this); 

    // default settings 
    var defaults = { 
      initialText: 'I have been initialized' 
     }; 
    // Merge defaults with setup options 
    var options = $.extend({}, defaults, options); 

    // Protect final options, placing inside jQuery element data 
    $this.data('myPlugSettings', options); 

    // Shortcut var to access option data 
    var settings = $this.data('myPlugSettings'); 

    // private methods 
    var fooPrivate = function() { 
     // do something private ... 
    }; 

    // public methods   
    this.changeText = function(param) { 
     $this.text(param); 
    }; 

    // Constructor 
    this.init = function() { 
     $this.text(settings.initialText); 
     // Return this for chainability? 
     return this; 
    }; 

    return this.init(); 
} 
})(jQuery); 



// globals 

_ = { 
    myPlugin: null, 
    myPluginTwo: null, 
    myPluginFoo: null 
} 


// Button Event handlers 

$("#btnLoadPlugs").click(function(e) { 
    _.myPlugin = $('#single').myPlugin({ 
     initialText: "Custom initial text" 
    }); 
    _.myPluginTwo = $('#anotherSingle').myPlugin(); 
    _.myPluginFoo = $('.foo').myPlugin(); 
}); 

$("#btnGoSingle").click(function(e) { 
    _.myPlugin.changeText(" Worked on single ID "); 
}); 

$("#btnGoAnotherSingle").click(function(e) { 
    _.myPluginTwo.changeText(" Worked again here "); 
}); 

$("#btnGoFoo").click(function(e) { 
    // THIS FALLS OVER ??????????? 
    _.myPluginFoo.changeText(" foos get this "); 
}); 

My JS Fiddle здесь делает этот вопрос очень легко понять.

+1

Вы возвращаетесь 'this' и ничего больше не запускаете? 'if (this.length> 1) { this.each (function() {$ (this) .myPlugin (options)}); верните это; } ' –

+0

Да! Итак ... мы удаляем 'return this' из вышеперечисленного и работает так, как ожидалось! Единственное препятствие заключается в том, что он нарушает цепную способность в этой ситуации, правильно - но ... угадайте, вы не можете получить свой торт и съесть его! Спасибо – Maz

ответ

2

TLDR

_.myPluginFoo теряет ссылку на JQuery объектов с changeText методом.

// support multiple elements 
if (this.length > 1){ 
    this.each(function() { $(this).myPlugin(options) }); 

    // Send the collection back. 
    return this; 
} 

Просто, чтобы заставить его работать

// This will work, but this is not exactly what you have intended. 
_.myPluginFoo.each(function(key, value) { 
    $(value).myPlugin().changeText('Hello'); 
}); 

Почему?

Это ожидаемое поведение селектора двигателя Sizzle, то $('#unique') вызова возвращает экземпляр JQuery Collection с одной HTMLElement, доступного $('#unique')[0].

Изменяя $('#unique') в this внутри $.fn.myPlugin, вы получите результирующий объект с changeThext собственности.

$('.foo').myPlugin() это приводит к this.length > 1 // true

Вы легко заметите разницу отладкой следующий код:

$("#btnLoadPlugs").click(function(e) { 
    // ... 

    console.log(_.myPluginTwo); // Single object. 
    console.log(_.myPluginFoo); // A collection, without changeText method. 
}); 

$.data защиты, вы используете не очень эффективно.

Лучший способ

Кроме того, вы могли бы реализовать что-то вроде $('.foo').myPlugin('changeText', 'new text'), если это имеет смысл.

Посмотрите на jQuery Boilerplate, это один из лучших вещей о плагинах jQuery.

+0

Спасибо за это. Действительно отличный ответ. JQuery Boilerplate, связанный выше, предлагает отличные решения. – Maz