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

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 для пространства имен.
Ауроврата
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.