Как вы принудительно запускаете свое javascript-событие, независимо от порядка добавления событий?

У меня есть javascript, который люди включают в свою страницу. В моем javascript у меня есть версия jQuery (1.8 для простой справки), которая разделяется на свое собственное пространство имен и ссылается через глобальную переменную (но не один из двух стандартных варов "$" или "jQuery" ), Это позволяет пользователям иметь jQuery на своей странице и не мешать тому, что я делаю внутренне в своих функциях.

Итак, у нас есть одна страница с jQuery уже (1.4), и все работает отлично, за исключением того, что пользователь и мой код одновременно прослушивают события "click" на элементах, а их первый - на нескольких событиях они возвращают false, jQuery останавливает распространение, и мое событие никогда не запускается. Мне нужно, чтобы мое мероприятие было первым. Пользователь ожидает, что мои функции onClick будут работать.

Теперь я знаю, что jQuery сохраняет свой собственный порядок событий внутри объекта _data(), и благодаря этому можно отпереть существующие события, привязать мое событие, а затем повторно привязать существующие события, но это применимо только к связанным объектам через этот экземпляр jQuery. Я бы предпочел не просто слепо искать объект jQuery в надежде, что конфликт был введен пользовательской версией jQuery. В конце концов, что происходит, когда пользователь связывает событие не через jQuery? Попытка манипулировать существующим объектом jQuery на странице не является хорошим решением.

Я знаю, что в зависимости от браузера они используют addEventListener/removeEventListener или attachEvent/detachEvent. Если бы я мог получить список уже добавленных событий, я мог бы перестроить их в том порядке, в котором я хотел, но я не могу понять, как это сделать. Просматривая DOM с помощью проверки хрома, я не вижу привязанного onclick (не на объекте, а не на окне или документе).

У меня самое страшное время, пытаясь выяснить, где именно JQuery связывает его прослушивание. Чтобы управлять порядком собственных событий, jQuery должен вслух прослушивать где-нибудь, а затем скрыть свои собственные функции? Если бы я мог понять, где это сделать, я мог бы получить представление о том, как обеспечить, чтобы мое событие всегда было первым. Или, может быть, есть какой-то javascript API, который мне не удалось найти в google.

Любые предложения?

Ответ 1

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

Ответ 2

Мы решили это, просто добавив небольшое расширение jQuery, которое вставляет события во главе цепочки событий:

$.fn.bindFirst = function(name, fn) {
  var elem, handlers, i, _len;
  this.bind(name, fn);
  for (i = 0, _len = this.length; i < _len; i++) {
    elem = this[i];
    handlers = jQuery._data(elem).events[name.split('.')[0]];
    handlers.unshift(handlers.pop());
  }
};

Затем, чтобы связать ваше событие:

$(".foo").bindFirst("click", function() { /* Your handler */ });

Легкий peasy!

Ответ 3

Я сталкиваюсь с противоположной ситуацией, когда меня попросили включить библиотеку, которая использует event.stopImmediatePropagation() для элемента, на наш сайт. Поэтому некоторые из моих обработчиков событий пропущены. Вот что я делаю (как ответил здесь):

<span onclick="yourEventHandler(event)">Button</span>

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

Ответ 4

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

Однако для полноты здесь есть одна возможность (полностью непроверенная, просто демонстрирующая общую концепцию):

// override createElement()
var temp = document.createElement;
document.createElement = function() {
    // create element
    var el = document.createElement.original.apply(document, arguments);

    // override addEventListener()
    el.addEventListenerOriginal = el.addEventListener;
    el._my_stored_events = [];

    // add custom functions
    el.addEventListener = addEventListenerCustom;
    el.addEventListenerFirst = addEventListenerFirst;
    // ...
};
document.createElement.original = temp;

// define main event listeners
function myMainEventListeners(type) {
    if (myMainEventListeners.all[type] === undefined) {
        myMainEventListeners.all[type] = function() {
            for (var i = 0; i < this._my_stored_events.length; i++) {
                var event = this._my_stored_events[i];
                if (event.type == type) {
                    event.listener.apply(this, arguments);
                }
            }
        }
    }
    return myMainEventListeners.all[type];
}
myMainEventListeners.all = {};

// define functions to mess with the event list
function addEventListenerCustom(type, listener, useCapture, wantsUntrusted) {
    // register handler in personal storage list
    this._my_stored_events.push({
        'type' : type,
        'listener' : listener
    });

    // register custom event handler
    if (this.type === undefined) {
        this.type = myMainEventListeners(type);
    }
}

function addEventListenerFirst(type, listener) {
    // register handler in personal storage list
    this._my_stored_events.push({
        'type' : type,
        'listener' : listener
    });

    // register custom event handler
    if (this.type === undefined) {
        this.type = myMainEventListeners(type);
    }
}

// ...

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