Как вы принудительно запускаете свое 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 в решении таких проблем.