Как иметь несколько экземпляров плагина jQuery на одной странице?

Я пишу простой плагин jQuery, но у меня не получается использовать несколько экземпляров на странице.

Например, вот пример плагина, иллюстрирующий мою точку зрения:

(function($) {
  $.fn.samplePlugin = function(options) {
    if (typeof foo != 'undefined')
    {
      alert('Already defined!');
    } else {
      var foo = 'bar';
    }
  };
})(jQuery);

И тогда, если я сделаю это:

$(document).ready(function(){
  $('#myDiv').samplePlugin({}); // does nothing
  $('#myDiv2').samplePlugion({}); // alerts "Already defined!"
});

Это, очевидно, слишком упрощенный пример, чтобы понять суть. Итак, мой вопрос: как мне получить два отдельных экземпляра подключаемого модуля? Я хотел бы иметь возможность использовать его в нескольких экземплярах на одной странице.

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

Спасибо за ваше руководство!


person James Skidmore    schedule 23.10.2009    source источник
comment
пример: gist.github.com/736705   -  person Toby    schedule 02.01.2011
comment
должно if (typeof foo == 'undefined') не быть if (typeof foo != 'undefined')   -  person Hailwood    schedule 07.02.2011
comment
@Хейлвуд, да, ты прав. Спасибо!   -  person James Skidmore    schedule 07.02.2011


Ответы (9)


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

когда вы определяете свои переменные внутри плагина, вы можете использовать .data() для хранения всех переменных, которые вы определяете

как это

(function($) {
  $.fn.samplePlugin = function(options) {
    var base = this;
    this.foo // define foo

    // do stuff with foo and other variables

    // Add a reverse reference to the DOM object
    this.data("pluginname", base);

  };})(jQuery);

И когда вы хотите использовать ту же переменную foo, вы должны получить ссылку следующим образом:

base = this.data("pluginname");
base.foo

Надеюсь, поможет

Логан

person Logan    schedule 27.09.2010

HTML:

<code class="resize1">resize1</code>
<code class="resize2">resize2</code>


<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"></script>
<script src="js/plugins.js"></script>
<script src="js/main.js"></script>
<script type="text/javascript">
       jQuery(document).ready(function($) {
           $('.resize1').ratiofix({message:'resize1'});
           $('.resize2').ratiofix({message:'resize2'});
       });
</script>

Я нашел 2 решения - первое - это фабрика виджетов jquery http://jqueryui.com/widget/ js код:

$.widget("custom.ratiofix",{
    options:{
        message:"nothing"
    },
    _create:function (){
        var self=this;
        this.setListeners();
    },
    setListeners:function (){
        var self=this;
        $(window).on('resize',$.proxy(self.printMsg,self));
    },
    printMsg:function (){
         console.log(this.options.message);
    }
});

И второй (без фабрики виджетов):

(function ($){
var Ratiofix = {
  init: function(options, elem) {
    this.options = $.extend({},this.options,options);
    this.elem  = elem;
    this.$elem = $(elem);
    this.setListeners();
    return this;
  },
  options: {
    message: "No message"
  },
  printMsg: function(){
     console.log(this.options.message);
  },
  setListeners:function (){
    var self=this;
    this.$elem.on('click',function (){
         console.log(self.options.message);
    });
    $(window).on('resize',$.proxy(self.printMsg, self));
  }
};

  $.fn.ratiofix=function (options){
    this.init= function(options, elem) {
      this.options = $.extend({},this.options,options);
      this.elem  = elem;
      this.$elem = $(elem);

      return this;
  };

    if ( this.length ) {
      return this.each(function(){
        var ratiofix = Object.create(Ratiofix);
        ratiofix.init(options, this); 
        $.data(this, 'ratiofix', ratiofix);
      });
    }


  };
})(jQuery);

В обоих случаях плагины работают отдельно и имеют свои настройки. В моем случае - 2 виджета слушают изменение размера окна и выводят на консоль собственные параметры.сообщение

person Roman Yudin    schedule 03.09.2013

Я не уверен, что вы подразумеваете под наличием более одного экземпляра плагина. Плагин будет доступен для использования на любом элементе.

Этот комментарий мало что проясняет для меня:

Итак, скажите, что это плагин, который принимает параметр «цвет» и превращает объект в этот цвет. Ну, в этом случае вам понадобится несколько экземпляров, так как вы имеете дело с более чем одним элементом страницы, меняющим более одного цвета.

В этом случае вы должны передать аргументы разными цветами по мере необходимости:

$('div#foo').makeColor('red');
$('div#bar').makeColor('blue');

Каждый раз, когда вы вызываете плагин, он будет использовать любые аргументы, которые вы ему зададите. Плагин не является классом, которому нужны экземпляры.

person Nathan Long    schedule 23.10.2009
comment
Спасибо, Натан, я ценю это! - person James Skidmore; 24.10.2009

Просто бросаю свое решение сюда:

(function ($){

    $.fn.plugin = function (options){
        var settings = $.extend({}, $.fn.plugin.defaults, options);
        settings.that = $(this);
        $.fn.plugin.init (settings);
    };

    $.fn.plugin.defaults = { objval: 'default' };

    $.fn.plugin.init = function (settings){
        settings.that.val (settings.objval);
    };

}( jQuery ));

$('#target1').plugin ({objval: 'not default'});
$('#target2').plugin ();

ДЕМО

Переменная настроек изолируется каждый раз, когда вы инициализируете объект.

person Scott M    schedule 22.02.2013

Чтобы ответить на ваш вопрос напрямую, вы можете использовать jQuery.noconflict(), чтобы избежать конфликтов пространств имен и, таким образом, потенциально иметь несколько экземпляров на странице.

var $j = jQuery.noConflict();
// Use jQuery via $j(...)
$j(document).ready(function() {
  // etc

проверьте здесь

Но я сомневаюсь в вашем дизайне. Почему вы пишете плагин, который, кажется, не работает с упакованным набором jQuery? .. Плагины должны быть написаны так, чтобы предполагать, что они работают с массивом jQuery, хранящимся в «этом». В этом случае любое состояние может быть сохранено в каждом из элементов, на которые воздействуют... Но, может быть, вы строите что-то другое?

Просмотрите эту страницу.

person Scott Evernden    schedule 23.10.2009

вместо того, чтобы писать это

$("#divid1").samplePlugin();
$("#divid2").samplePlugin();

ты можешь сделать так

$.plugin('samplePlugin1', samplePlugin);
$("#divid1").samplePlugin1();

$.plugin('samplePlugin2', samplePlugin);
$("#divid2").samplePlugin2();

Подробную информацию можно найти здесь http://alexsexton.com/?p=51

person manny    schedule 02.06.2011

Вам нужно использовать this.foo вместо var foo, чтобы переменная была связана только с текущим объектом.

person WhyNotHugo    schedule 02.08.2012

Это сработало для меня! У меня были определенные параметры, для каких страниц/мест я хотел запустить плагин, и я смог добиться успеха, используя простой оператор if. Надеюсь, это поможет кому-то!

<!-- Begin JQuery Plugin Foo -->
<script src="js/foo_fun.js"></script>

<?php 
if(substr_count(strtolower($currentUrl),"member")>0)
{
?>
    <script>
    $(document).ready(function(){
        $('#vscroller').vscroller({newsfeed:'news_employee.xml', speed:1000,stay:2000,cache:false});
    });
    </script>
<?php
}
else
{
?>
    <script>
    $(document).ready(function(){
        $('#vscroller').vscroller({newsfeed:'news_company.xml', speed:1000,stay:2000,cache:false});
    });
    </script>
<?php
}
?>
<!-- End JQuery Foo--> 
person steph    schedule 01.01.2012
comment
Это больше похоже на взлом! Если на вашей странице есть много мест, где вам нужно сделать это, это сделает ваш код менее читаемым и запутанным. Лучший вариант — исправить основную причину, то есть множественную инициализацию плагина. - person Vishnu Narang; 30.12.2013

У меня была та же проблема: как использовать много экземпляров плагина только в одной форме? Обычный способ не работает, потому что на самом деле экземпляр не является экземпляром плагина: это экземпляр jQuery. Таким образом, если для управления плагином определено более одного элемента, каждое определение переопределяет предыдущие параметры.

Нужно было взглянуть на проблему с другой стороны.

Плагин обычно предназначен для реакции на определенное событие для определенного элемента. например, при нажатии на кнопку или когда мышь находится над элементом. В моем случае мне пришлось использовать плагин автозаполнения для поля города, но моя форма имеет 5 вкладок и всего 4 поля для городов для сбора 4 разных частей информации. Для каждого поля параметры специфичны.

Кстати, я понял, что мне не нужно активировать плагин каждый раз: достаточно просто по соответствующему событию в поле.

Так у меня появилась идея: менеджер событий для каждого элемента. Когда событие добавляется, я определяю действие плагина. Некоторый код будет более эффективным для объяснения: представьте, что у вас есть 3 блока div, и ваш плагин должен изменить цвета, но с конкретными цветами в зависимости от того, какой div затронут.


$(document).ready(function(){
    // Wich elements are affected by the plugin
    var ids = ['myDiv1','myDiv2','myDiv3'];
    // foe each one :
    for (v in ids) 
    {
        //define from an event :
        $('#'+ ids[v]).focus(function()
        {
            // depending which id is active :
            var  aParams, idDiv = $(this).attr('id');
            // Choosing the right params
            switch(idDiv)
            {
                case 'myDiv1':
                    aParams = {'color': '#660000', 'background-color': '#0000ff'};
                    break;
                case 'myDiv2':
                    aParams = {'color': '#006600', 'background-color': '#ff00ff'};
                    break;
                case 'myDiv3':
                    aParams = {'color': '#000066', 'background-color': '#ff0000'};
                    break;
                default:
                    aParams = {'color': '#000000', 'background-color': '#ffffff'};
            };
            // Defining the plugin on the right element with the right params
            $(this).myPlugin(
            {
                colors: aParams
            });
        });
    }
});

И это прекрасно работает.

Извините, если мой английский не идеален - надеюсь, вы хорошо понимаете.

person Cyrano_fr    schedule 19.08.2010