Пользовательское событие в 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);