Пользовательское событие в jQuery, которое не связано с элементом DOM?

Мне интересно, возможно ли создать пользовательское событие в jQuery, которое не связано с элементом DOM.

Я очень предпочитаю jQuery для YUI, но есть одна вещь в YUI, которая мне нравится, которая создает пользовательские события и может подписаться на них позже.

Например, это создает событие, привязанное к переменной, а не к элементу DOM:

var myevent = new YAHOO.util.CustomEvent("mycustomevent");

Все примеры и документация, которые я читал для jQuery, требуют:

$('body').bind('mycustomevent', function(){
    //do stuff
});

Ответ 1

Вы можете запускать пользовательские глобальные события, подобные этому в jQuery:

jQuery.event.trigger('mycustomevent', [arg1, arg2, arg3]);

Они будут запускаться для любого элемента.

Так как jQuery построен вокруг объектов DOM, вы должны привязать свои события к объектам DOM. Вероятно, вы можете найти способ связать события без элемента (вы это сделали), но это не поддерживаемая методология.

Как вы писали в своем собственном ответе, вы можете привязать свое событие к глобальному объекту DOM, если вы не хотите привязывать его к отдельному элементу страницы:

$(document).bind('mycustomevent', function (e, arg1, arg2, arg3) { /* ... */ });

Ответ 2

Согласно комментарий Джона Ресига, привязки событий к пользовательским объектам через jQuery поддерживается:

Нет особых причин, по которым он не документирован (кроме того, что он довольно нетрадиционен для большинства пользователей) - но да, мы поддерживаем его и имеем для него модульные тесты.

Итак, это работает:

var a = {foo: 'bar'};
$(a).on('baz', function() {console.log('hello')});
$(a).triggerHandler('baz');
>>> 'hello'

Для большинства пользователей потребуется triggerHandler(), а не trigger(). Если используется .trigger("eventName"), он будет искать свойство "eventName" на объекте и попытаться выполнить его после выполнения всех обработчиков jQuery (Source).

EDIT (28.02.2017):

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

Ответ 3

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

Чтобы связать пользовательское событие:

$().bind('mycustomevent', function(){
    //code here
});

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

$({mydata:'testdata'}).bind('mycustomevent',function(){
    //code here
});

Ответ 4

Связывание с элементами не-dom было удалено в jQuery 1.4.4.

Ответ 5

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

$(document).ready(function() {

  $(body).append('<div id="receiver">');

  $("#receiver").bind("foo_event", function () {
    // decide what to do now that foo_event has been triggered.
  });

  $("#some_element").click(function() {
    $("#receiver").trigger("foo_event");
  });

});

Ответ 6

jQuery Callbacks предоставляет простой способ реализовать систему pub-sub, независимую от DOM.

В нижней части связанной страницы приведен пример кода, который показывает, как это сделать.

Ответ 7

[EDIT]

Здесь рабочий класс, который использует понятия, написанные ниже:

https://github.com/stratboy/image-preloader

Это просто предварительный загрузчик последовательного изображения. Вы можете подписаться на кучу событий. Посмотрите.

[/EDIT]

Старый пост:

Вот еще один пример с болотными экранами с обратными вызовами, предложенными Himanshu P.

Я создаю класс, и я пришел из Mootools, где такие вещи, как Classes и пользовательские события, непосредственно реализованные в классах (поэтому не привязанные к элементам DOM), абсолютно естественны. Поэтому я попробовал какое-то обходное решение и поделился ниже.

  var step_slider;

  //sandbox
  ;(function($) {

//constructor
var StepSlider = function(slider_mask_selector,options) {

    //this.onStep = $.Event('step');
    this.options = null;
    this.onstep = $.Callbacks();

    this.init();
}//end constructor

StepSlider.prototype = {

    init:function(){
        this.set_events();
    },//end init

    set_events:function(){

        if(this.options){
            if(this.options.onstep){
                this.subscribe('step',options.onstep);
            }
        }

    },//set_events

    subscribe:function(event,action){
        this['on'+event].add(action);
    },

    fire_onstep:function(){
        this.onstep.fire({ data1:'ok' });
    }

}//end prototype/class

//--------------------

$(document).ready(function() {

    step_slider = new StepSlider('selector');

    //for example, say that you have a div#next-button, you can then do this:
    $('#next-button').click(function(){
        step_slider.fire_onstep();
    });

});//end domready


})(jQuery);