Как использовать jQuery в (..) для динамического связывания с несколькими событиями
Я пытаюсь создать jQuery.on() (ex-live()) для привязки нескольких событий. Он работает для элементов, которые существуют на document.ready, но если я динамически добавляю вторую ссылку после загрузки страницы, мой обработчик событий не запускается.
Это имеет смысл, поскольку метод внешнего метода выполняет итерации по элементам, и doenst прослушивает недавно добавленные узлы DOM и т.д..on(..) - это то, что прослушивает новые узлы DOM, но требует параметров имени события, которого у меня нет, пока у меня не будет DOM node.
Похоже на цыпленок и ситуацию с яйцом.
Мысли?
<a href="/foo.html" class="js-test" data-test-events="['click', 'mouseover']">Test 1</a>
<a href="/foo.html" class="js-test" data-test-events="['mouseout']">Test 2</a>
$(function() {
$('.js-test').each(function() {
var $this = $(this);
var e, events = $this.data('test-events');
for(e in events) {
$this.on(events[e], function() {
console.log("hello world!")
});
}
});
});
Обновление. Кажется, что работает следующее: $(this), похоже, не находится в правильной области.
<a href="/foo.html" class="js-test" data-test-events="click mouseover">Test 1</a>
<a href="/foo.html" class="js-test" data-test-events="mouseout">Test 2</a>
$(function() {
$('.js-test').on($(this).data('test-events'), function() {
// call third party analytics with data pulled of 'this'
});
});
Обновление 1:
Я считаю, что лучшим вариантом будет создание специальных методов .on для всех методов, которые я хочу поддерживать так:
$(document).on('click', '.js-test[data-test-events~="click"]' function(event) {
record(this, event);
});
$(document).on('mouseover', '.js-test[data-test-events~="mouseover"]', function(event) {
record(this, event);
});
... etc ...
Ответы
Ответ 1
$('a.js-test').on('click mouseover', function(event) {
// you can get event name like following
var eventName = event.type; // return mouseover/ click
console.log(eventName);
// you code
console.log('Hello, World!');
});
Пример примера
Если вы хотите что-то вроде live-события, то:
$('body').on('click mouseover', 'a.js-test', function(event) {
// you can get event name like following
var eventName = event.type; // return mouseover/ click
console.log(eventName);
// you code
console.log('Hello, World!');
});
В соответствии с вашим последним правлением попробуйте следующее:
$('.js-test').on($('.js-test').data('test-events'), function() {
console.log("hello world!")
});
Пример примера для редактирования
и для передачи живых событий
$('body').on($('.js-test').data('test-events'), '.js-test', function() {
console.log("hello world!")
});
Ответ 2
Боясь, что вы не можете этого сделать, потому что вам нужно предоставить jQuery либо с элементами DOM, либо с именами событий.
Вы можете связать события с новыми элементами DOM вручную или связать все возможные события, которые могут быть в событиях-тестах данных (если у вас есть 3-5 из них, при всех событиях DOM это станет глупым и медленным решением) и проверьте, элемент имеет один из них:
$('body').on("mouseover click mouseout mouseenter mouseleave", '.js-test', function(e) {
if (!$.inArray(e.type, $(this).data('test-events').split(' '))) {
return;
}
console.log("hello world!");
});
Ответ 3
Если вы хотите инициировать событие всякий раз, когда соответствующий элемент добавляется в DOM, вы можете посмотреть на livequery - http://docs.jquery.com/Plugins/livequery.
Ответ 4
Этот код позволит вам зарегистрировать несколько обработчиков событий как массив функций. Он тестировался и работал. Смотрите демонстрационные версии jsfiddle и тестовые примеры.
JavaScript:
$(document).ready(function() {
eventFnArray = [];
eventFnArray["click"] = function(e) {
if(e.type != "click") return ;
alert("click event fired - do xyz here");
// do xyz
};
eventFnArray["mouseover"] = function(e) {
if(e.type != "mouseover") return ;
alert("mouseover fired - do abc here");
// do abc
};
eventFnArray["mouseout"] = function(e) {
if(e.type != "mouseout") return ;
alert("mouseout fired - do JKL here");
// do JKL
};
$('.js-test').each( (function(fn) {
return function(i) {
if(i != 0) return;
var _that = this;
var events = [];
events = $(_that).attr("data-events").split(" ");
// alert($(_that).attr("data-events") + " : " + events.join(" "));
$(this).parent().on(
events.join(" "),
'.js-test',
function() {
console.info("hello - this is the " + event.type + " event");
// alert("data-events = " + $(this).attr("data-events") + " : event.type = " + event.type);
// delegate to the correct event handler based on the event type
if($(this).attr("data-events").indexOf(event.type) != -1)
fn[ event.type ](event);
}
);
}
})(eventFnArray)); // pass function array into closure
});
HTML:
<div id="container">
<a href="#" class="js-test" data-events="click mouseout mouseover">Test 1</a>
<a href="#" class="js-test" data-events="mouseover">Test 2</a>
</div>
Тестирование добавления дополнительных элементов:
Вот три тестовых примера:
// adds a link with the click event attached.
$('#container').append("<a href='#' class='js-test' data-events='click'>TEst333</a>");
// adds a link with the mouseover event
$('#container').append("<a href='#' class='js-test' data-events='mouseover'>TEst444</a>");
// adds a link with mouseout
$('#container').append("<a href='#' class='js-test' data-events='mouseout'>TEs555</a>");
// adds a link with both mouseover and mouseout attached
$('#container').append("<a href='#' class='js-test' data-events='mouseout mouseover'>TEstLast</a>");
// mouseout and click
$('#container').append("<a href='#' class='js-test' data-events='mouseout click'>TEstLastForREAL</a>");
Осторожно:
Я заметил, что в одной из ваших ссылок есть и клик, и указатель мыши. Хотя этот код будет обрабатывать несколько событий для каждой ссылки, как показано в последнем тестовом случае, событие click не будет срабатывать, если присутствует событие mouseover.
Это не ошибка в приведенном выше коде, а в том, как обрабатываются события, как показано здесь:
// mouseover and mouseout fire, but not the click event
$('#container').on('mouseover mouseout click', '.js-test',function() { alert("afdas " + event.type); });