Спеціальні події в jQuery?


180

Я шукаю деякий вклад про те, як найкращим чином реалізувати власні події в jquery. Я знаю, як підключити події з елементів dom, таких як "click" тощо, але я будую крихітну бібліотеку / плагін JavaScript, щоб обробляти деякі функції попереднього перегляду.

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

То як мені це зробити? Чи я не помічав деякий вбудований функціонал у jquery, щоб підняти / обробляти події користувачів чи мені потрібен плагін jquery, щоб це зробити? Як ви вважаєте, що це найкращий спосіб / плагін для вирішення цього питання?


3
Є ще одна основа, knockoutjs.com, яка насправді може вирішити мою стару проблему, якщо хтось, хто дивиться на це питання, потребує цього.
Per Hornshøj-Schierbeck

2
Бачачи, що я продовжую отримувати репутацію з цього питання, люди все ще повинні його читати. Я просто хочу оновити свій поточний вибір mvc на базі клієнта: angularjs.org
Per Hornshøj-Schierbeck

Навіть незважаючи на те, що він повністю відрізняється від angular v1, Angular2 ( angular.io ) демонструє таку велику обіцянку і буде моїм першим вибором, коли він вийде з бета / rc.
Per Hornshøj-Schierbeck

Відповіді:


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]);
            }
        });
    };
};

Демонстрацію демонстрації можна переглянути тут. Налаштуйте браузер працювати в режимі офлайн і подивіться, що відбувається…. ні, це не дуже захоплююче.

Запустити і зв’язати

Що захоплююче, хоча (або принаймні те, що мене хвилює), це метод, за допомогою якого стан передається через додаток. Я натрапив на багато в чому не обговорюваний метод реалізації паб / підсистеми, використовуючи тригерні та прив'язні методи jQuery.

Демо-код більш тупий, ніж повинен бути. Об'єкт виявлення мережі публікує події "статусу" в документі, який активно їх слухає, і, в свою чергу, публікує події "сповіщення" всім підписникам (докладніше про них пізніше). Причина цього полягає в тому, що в реальному застосуванні, ймовірно, буде ще якась логіка, яка контролює, коли і як публікуються події "сповіщення".

$(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
    */
});

Через централізований підхід DQ jQuery події публікуються (запускаються на) елементах DOM. Це може бути вікно або документ об'єкта для загальних подій або ви можете створити об’єкт jQuery за допомогою селектора. Підхід, який я застосував із демонстрацією, полягає у створенні майже просторового підходу до визначення абонентів.

Елементи DOM, які мають бути абонентами, класифікуються просто з "абонентом" та "мережевим виявленням". Потім ми можемо публікувати події лише для цих елементів (з яких у демонстрації є лише один), ініціюючи подію сповіщення на$(“.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
Це звідкись цитата? Якщо це так, будь ласка, цитуйте своє джерело та надайте посилання, якщо воно все ще існує.
Aryeh Leib Taurog

1
Так, це цитата, в історії редагування це посилання , на даний момент воно недоступне. Архівна сторінка тут .
Stano

1
Бен Алман написав крихітний (крихітний крихітний крихітний) jQuery pub sub plugin . Це надзвичайно елегантно.
Барні

127

Посилання, що надається у прийнятій відповіді, показує хороший спосіб реалізувати паб / підсистему за допомогою 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
Мені дуже подобається ця відповідь. Будь-хто може прочитати документи на тригер () 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
Я шукаю спосіб підняти подію та запустити передплатників / слухачів. Не запускати його вручну, оскільки об’єкт, що піднімає, не знає, хто слухає ...
Per Hornshøj-Schierbeck

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 .. але мені було цікаво, чи існує більш ефективний спосіб.
Адді

Гарний вилов на цю помилку. Так, якщо ви зміните рядок 5 від обробника (ev); до: handler.call (це, ev); тоді цей аргумент буде таким, як це зазвичай є у стандартних обробниках подій jquery. jsfiddle.net/b9chris/VwEb9
Кріс

Ви також знаєте спосіб реалізувати це навпаки? Я намагаюся використовувати цей приклад, але з scroll, який не поширюється. Я думаю, що замість того, щоб слухачів було жорстко зафіксовано до тіла, мені потрібні елементи, які onпов'язані з ними -вентом, щоб вони самі розпочали подію.
Густ ван де Валь

Я не впевнений у сценарії, про який ви питаєте; може бути найкраще задати питання як зразок коду?
Кріс Москіні

9

Це стара публікація, але я спробую оновити її новою інформацією.

Для використання спеціальних подій вам потрібно прив’язати його до якогось елемента DOM та запустити його. Тому потрібно використовувати

Метод .on () приймає в якості аргументів тип події та функцію обробки подій. Необов'язково, він також може отримувати пов'язані з подіями дані як свій другий аргумент, підштовхуючи функцію обробки подій до третього аргументу. Будь-які передані дані будуть доступні функції обробки подій у властивості даних об'єкта події. Функція обробки подій завжди отримує об'єкт події як його перший аргумент.

і

Метод .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"] );

Приємне пояснення можна знайти тут і тут . Чому саме це може бути корисним? Я дізнався, як це використовувати в цьому відмінному поясненні від інженера Twitter .

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.