Пользовательские события в jQuery?

180

Я ищу некоторую информацию о том, как наилучшим образом реализовать пользовательскую обработку событий в jquery. Я знаю, как подключать события от элементов dom, таких как «щелчок» и т. Д., Но я создаю крошечную библиотеку / плагин javascript для обработки некоторых функций предварительного просмотра.

У меня запущен скрипт для обновления некоторого текста в элементе dom из набора правил и ввода данных / данных, которые я получил, но теперь мне нужен тот же текст, показанный в других элементах, о которых этот скрипт не может знать. Мне нужен хороший шаблон, чтобы как-то наблюдать, как этот скрипт производит необходимый текст.

Так как мне это сделать? Я пропустил некоторые встроенные функции в jquery для создания / обработки пользовательских событий или мне нужен какой-нибудь плагин jquery для этого? Какой, по вашему мнению, лучший способ / плагин для этого?

Пер Хорншой-Ширбек
источник
3
Есть еще один фреймворк, knockoutjs.com, который действительно может решить мою старую проблему, если кому-то, кто ищет этот вопрос, это нужно.
Пер Хорншой-Ширбек,
2
Видя, что я продолжаю получать репутацию от этого вопроса, люди все еще должны читать его. Я просто хочу обновить свой текущий выбор клиентских mvc-фреймворков: angularjs.org
Per Hornshøj-Schierbeck
Несмотря на то, что Angular2 ( angular.io ) полностью отличается от angular v1, он обещает очень многое и станет моим первым выбором, когда он выйдет из бета / rc.
Пер Хорншой-Ширбек

Ответы:

105

Взгляните на это:

(перепечатано со страницы блога с истекшим сроком действия http://jamiethompson.co.uk/web/2008/06/17/publish-subscribe-with-jquery/ на основе архивной версии по адресу http://web.archive.org/web /20130120010146/http://jamiethompson.co.uk/web/2008/06/17/publish-subscribe-with-jquery/ )


Публикация / подписка с помощью jQuery

17 июня 2008 г.

В целях написания пользовательского интерфейса jQuery, интегрированного с автономной функциональностью Google Gears, я играл с некоторым кодом для опроса состояния сетевого подключения с помощью jQuery.

Объект обнаружения сети

Основная предпосылка очень проста. Мы создаем экземпляр объекта обнаружения сети, который будет регулярно опрашивать URL-адрес. В случае сбоя этих HTTP-запросов мы можем предположить, что сетевое соединение потеряно или сервер просто недоступен в настоящее время.

$.networkDetection = function(url,interval){
    var url = url;
    var interval = interval;
    online = false;
    this.StartPolling = function(){
        this.StopPolling();
        this.timer = setInterval(poll, interval);
    };
    this.StopPolling = function(){
        clearInterval(this.timer);
    };
    this.setPollInterval= function(i) {
        interval = i;
    };
    this.getOnlineStatus = function(){
        return online;
    };
    function poll() {
        $.ajax({
            type: "POST",
            url: url,
            dataType: "text",
            error: function(){
                online = false;
                $(document).trigger('status.networkDetection',[false]);
            },
            success: function(){
                online = true;
                $(document).trigger('status.networkDetection',[true]);
            }
        });
    };
};

Вы можете посмотреть демо здесь. Настройте браузер на работу в автономном режиме и посмотрите, что произойдет ... нет, это не очень интересно

Триггер и связывание

Что интересно (хотя бы то, что меня волнует), так это метод, с помощью которого статус передается через приложение. Я наткнулся на практически не обсуждаемый метод реализации системы pub / sub с использованием методов триггера и связывания в jQuery.

Демо-код более тупой, чем нужно. Объект обнаружения сети публикует события «status» в документе, который активно их прослушивает, и, в свою очередь, публикует события «notify» всем подписчикам (подробнее об этом позже). Причиной этого является то, что в реальном приложении, вероятно, было бы больше логики, управляющей тем, когда и как публикуются события «уведомлять».

$(document).bind("status.networkDetection", function(e, status){
    // subscribers can be namespaced with multiple classes
    subscribers = $('.subscriber.networkDetection');
    // publish notify.networkDetection even to subscribers
    subscribers.trigger("notify.networkDetection", [status])
    /*
    other logic based on network connectivity could go here
    use google gears offline storage etc
    maybe trigger some other events
    */
});

Из-за подхода JQuery, ориентированного на DOM, события публикуются (запускаются) на элементах DOM. Это может быть объект окна или документа для общих событий или вы можете сгенерировать объект jQuery с помощью селектора. Подход, который я использовал для демонстрации, заключается в создании почти пространственного подхода к определению подписчиков.

Элементы DOM, которые должны быть подписчиками, просто классифицируются как «subscriber» и «networkDetection». Затем мы можем публиковать события только для этих элементов (из которых только один в демоверсии), вызывая событие уведомления$(“.subscriber.networkDetection”)

#notifierДИВ , который является частью .subscriber.networkDetectionгруппы абонентов , то есть анонимная функция , связанная с ней, эффективно действуя в качестве слушателя.

$('#notifier').bind("notify.networkDetection",function(e, online){
    // the following simply demonstrates
    notifier = $(this);
    if(online){
        if (!notifier.hasClass("online")){
            $(this)
                .addClass("online")
                .removeClass("offline")
                .text("ONLINE");
        }
    }else{
        if (!notifier.hasClass("offline")){
            $(this)
                .addClass("offline")
                .removeClass("online")
                .text("OFFLINE");
        }
    };
});

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

Витор Сильва
источник
Именно то, что я искал. Он, вероятно, прав, что это путь, но я не могу не думать, что jquery нужна либо прямая поддержка, либо плагин для более изящной обработки. Я подожду немного и посмотрю, есть ли другие
варианты решения
6
Это цитата откуда-то? Если это так, пожалуйста, укажите свой источник и укажите ссылку, если она еще существует.
Арье Лейб Таурог
1
Да, это цитата, в истории редактирования есть эта ссылка , в настоящее время она недоступна. Архивная страница находится здесь .
Стано
1
Бен Алман написал крошечный (крошечный крошечный крошечный) плагин jQuery pub . Это очень элегантно.
Барни
127

Ссылка, приведенная в принятом ответе, показывает хороший способ реализации системы pub / sub с использованием jQuery, но я нашел код несколько сложным для чтения, поэтому вот моя упрощенная версия кода:

http://jsfiddle.net/tFw89/5/

$(document).on('testEvent', function(e, eventInfo) { 
  subscribers = $('.subscribers-testEvent');
  subscribers.trigger('testEventHandler', [eventInfo]);
});

$('#myButton').on('click', function() {
  $(document).trigger('testEvent', [1011]);
});

$('#notifier1').on('testEventHandler', function(e, eventInfo) { 
  alert('(notifier1)The value of eventInfo is: ' + eventInfo);
});

$('#notifier2').on('testEventHandler', function(e, eventInfo) { 
  alert('(notifier2)The value of eventInfo is: ' + eventInfo);
});
Мануэль Наварро
источник
10
Мне очень нравится этот ответ. Любой может прочитать документацию по trigger () bind () (и on ()), но этот ответ предоставляет конкретный пример создания шины событий (pub / sub system) с использованием jquery.
lostdorje
1
Браво. Все, что мне нужно было знать.
Патрик Фишер
Я обнаружил, что если вы передаете массив (где длина> 1), когда вы запускаете пользовательское событие, то слушатель получит все элементы массива в своих аргументах, так что вы получите nчисло аргументов.
vsync
решение для обработки нескольких аргументов в слушателе:var eventData = [].slice.call(arguments).splice(1)
vsync
2
Есть ли способ сделать это без фиктивных элементов #notifier? Если у меня была библиотека javascript и я хотел, чтобы объект представлял событие, я не могу быть уверен, какие элементы существуют на странице.
AaronLS
21

Я так думаю .. можно «связать» пользовательские события, например (из: http://docs.jquery.com/Events/bind#typedatafn ):

 $("p").bind("myCustomEvent", function(e, myName, myValue){
      $(this).text(myName + ", hi there!");
      $("span").stop().css("opacity", 1)
               .text("myName = " + myName)
               .fadeIn(30).fadeOut(1000);
    });
    $("button").click(function () {
      $("p").trigger("myCustomEvent", [ "John" ]);
    });
Tuxified
источник
1
Я ищу способ поднять событие и вызвать на него подписчиков / слушателей. Не вызывайте его вручную, поскольку поднимающий объект не знает, кто его слушает ...
Пер Хорншой-Ширбек
2
Этот код делает это, не так ли? myCustomEventподнят, привязка сверху добавляет слушателя.
Sprintstar
15

У меня был похожий вопрос, но на самом деле я искал другой ответ; Я ищу, чтобы создать пользовательское событие. Например, вместо того, чтобы всегда говорить это:

$('#myInput').keydown(function(ev) {
    if (ev.which == 13) {
        ev.preventDefault();
        // Do some stuff that handles the enter key
    }
});

Я хочу сократить это до этого:

$('#myInput').enterKey(function() {
    // Do some stuff that handles the enter key
});

триггер и связывание не рассказывают всю историю - это плагин JQuery. http://docs.jquery.com/Plugins/Authoring

Функция «enterKey» присоединяется как свойство к jQuery.fn - это необходимый код:

(function($){
    $('body').on('keydown', 'input', function(ev) {
        if (ev.which == 13) {
            var enterEv = $.extend({}, ev, { type: 'enterKey' });
            return $(ev.target).trigger(enterEv);
        }
    });

    $.fn.enterKey = function(selector, data, fn) {
        return this.on('enterKey', selector, data, fn);
    };
})(jQuery);

http://jsfiddle.net/b9chris/CkvuJ/4/

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

$('a.button').on('click enterKey', function(ev) {
    ev.preventDefault();
    ...
});

Изменения: обновлено для правильной передачи правильного thisконтекста обработчику и для возврата любого возвращаемого значения из обработчика в jQuery (например, если вы хотели отменить событие и всплывающее окно). Обновлен для передачи корректного объекта события jQuery обработчикам, включая код ключа и возможность отмены события.

Старый jsfiddle: http://jsfiddle.net/b9chris/VwEb9/24/

Крис Москини
источник
Крис - Функция работала отлично. Единственное, что не работает, - это доступ к этой переменной. Я могу получить к ней доступ, используя e.currentTarget ..., но мне было интересно, есть ли более эффективный способ.
Addy
Хорошо поймать эту ошибку. Да, если вы измените строку 5 из обработчика (ev); to: handler.call (это, ev); тогда аргумент this будет, как обычно, в стандартных обработчиках событий jquery. jsfiddle.net/b9chris/VwEb9
Крис Москини
Вы также знаете способ реализовать это наоборот? Я пытаюсь использовать этот пример, но с scroll, который не распространяется. Я думаю, что вместо того, чтобы жестко onпривязать слушателей к телу, мне нужны элементы, которые связаны с событием -event, чтобы самим запустить событие.
Гаст ван де Валь
Gust Я не уверен в сценарии, о котором ты спрашиваешь; может быть лучше задать вопрос с примером кода?
Крис Москини
9

Это старый пост, но я постараюсь обновить его новой информацией.

Чтобы использовать пользовательские события, вам нужно привязать его к некоторому элементу DOM и вызвать его. Так что вам нужно использовать

Метод .on () принимает тип события и функцию обработки события в качестве аргументов. Необязательно, он также может получать связанные с событием данные в качестве второго аргумента, передавая функцию обработки событий третьему аргументу. Любые переданные данные будут доступны для функции обработки событий в свойстве data объекта события. Функция обработки событий всегда получает объект события в качестве первого аргумента.

и

Метод .trigger () принимает тип события в качестве аргумента. При желании он также может принимать массив значений. Эти значения будут переданы в функцию обработки событий в качестве аргументов после объекта события.

Код выглядит так:

$(document).on("getMsg", {
    msg: "Hello to everyone",
    time: new Date()
}, function(e, param) {
    console.log( e.data.msg );
    console.log( e.data.time );
    console.log( param );
});

$( document ).trigger("getMsg", [ "Hello guys"] );

Хорошее объяснение можно найти здесь и здесь . Почему именно это может быть полезно? Я нашел, как использовать это в этом превосходном объяснении от инженера Твиттера .

PS В простом javascript вы можете сделать это с новым CustomEvent , но остерегайтесь проблем с IE и Safari.

Сальвадор Дали
источник
3

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

var event = jQuery.Event('customEventName');
$(element).trigger(event);

Конечно, вы могли бы просто сделать

$(element).trigger('eventname');

Но способ, который я написал, позволяет вам определить, предотвратил ли пользователь дефолт или нет, выполнив

var prevented = event.isDefaultPrevented();

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


Я тогда обычно слушаю такие события

$(element).off('eventname.namespace').on('eventname.namespace', function () {
    ...
});

Еще раз, вы могли бы просто сделать

$(element).on('eventname', function () {
    ...
});

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

Нет ничего плохого в следующем:

$(element).on('eventname', function () {});

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

$(element).off('eventname', function () {});

Это удалит все eventnameсобытия из $(element). Вы не можете знать, будет ли кто-то в будущем также связывать событие с этим элементом, и вы бы случайно отменили привязку и к этому событию.

Безопасный способ избежать этого - это пространство имен для ваших событий, выполнив

$(element).on('eventname.namespace', function () {});

Наконец, вы могли заметить, что первая строка

$(element).off('eventname.namespace').on('eventname.namespace', ...)

Лично я всегда отменяю привязку события, прежде чем связать его, просто чтобы убедиться, что один и тот же обработчик события никогда не вызывается несколько раз (представьте, что это была кнопка отправки в форме оплаты, а событие было связано 5 раз)

Люк Мадханга
источник
хороший подход. +1 для пространства имен.
Ауроврата