Javascript эквивалентен $.on
Как кто-то, кто (к сожалению) узнал больше jQuery
, чем raw javascript
, я просто сейчас трачу время, чтобы заменить весь мой код raw javascript
. Нет, это не нужно, но мне легче учиться. Проблема, с которой я сталкиваюсь, заключается в преобразовании всех моих $(document).on
с raw javascript
. Мой сайт является "одностраничным приложением", и большинство моих фактических HTML
находятся в разных файлах, которые вызывается через запросы Ajax
. Итак, мой вопрос: как я могу искать event
из динамически загруженного контента? Я предполагаю, что мне пришлось бы добавить к ним событие onclick
, но как это сделать, jQuery
делает это без необходимости onclick
event
?
Ответы
Ответ 1
Привязка обработчиков в нативном API выполняется с помощью addEventListener()
.
Чтобы эмулировать делегирование событий jQuery, вы можете довольно легко создать систему, которая использует метод .matches()
для проверки .matches()
вами селектора.
function delegate(el, evt, sel, handler) {
el.addEventListener(evt, function(event) {
var t = event.target;
while (t && t !== this) {
if (t.matches(sel)) {
handler.call(t, event);
}
t = t.parentNode;
}
});
}
Вероятно, необходимо сделать некоторые изменения, но в основном это функция, которая принимает элемент для привязки, например, document
, тип события, селектор и обработчик.
Он начинается с e.target
и пересекает родителей, пока не e.target
связанного элемента. Каждый раз он проверяет, соответствует ли текущий элемент селектору, и, если это так, он вызывает обработчик.
Так что вы бы назвали это так:
delegate(document, "click", ".some_elem", function(event) {
this.style.border = "2px dashed orange";
});
Здесь живая демонстрация, которая также добавляет динамические элементы, чтобы показать, что новые элементы также подобраны.
function delegate(el, evt, sel, handler) {
el.addEventListener(evt, function(event) {
var t = event.target;
while (t && t !== this) {
if (t.matches(sel)) {
handler.call(t, event);
}
t = t.parentNode;
}
});
}
delegate(document, "click", ".some_elem", function(event) {
this.parentNode.appendChild(this.cloneNode(true));
this.style.border = "2px dashed orange";
});
<div>
<p class="some_elem">
<span>
CLICK ME
</span>
</p>
</div>
Ответ 2
Вот JavaScript, эквивалентный on()
JQuery
$(document).on('click', '#my-id', callback);
function callback(){
...handler code here
}
Javascript
document.addEventListener('click', function(event) {
if (event.target.id == 'my-id') {
callback();
}
});
function callback(){
...handler code here
}
При таком подходе идея состоит в том, чтобы использовать event.target. Конечно, по мере изменения селектора ваш код будет становиться все более вовлеченным
Ответ 3
В современных браузерах вы можете использовать Element.closest()
чтобы упростить репликацию метода jQuery .on()
а также обеспечить захват событий, всплывающих из дочерних элементов целевого элемента (нюанс, который пропускают некоторые другие реализации). В старых браузерах, включая IE, для этого потребуется полифилл.
const on = (element, event, selector, handler) => {
element.addEventListener(event, e => {
if (e.target.closest(selector)) {
handler(e);
}
});
}
on(document, 'click', '#test', e => {
console.log('click');
});
<button id="test">
Clickable
<i>Also Clickable</i>
</button>
Ответ 4
Другой подход для современных браузеров будет выглядеть примерно так:
const on = (selector, event, handler, element=document) => {
element.addEventListener(event, (e) => { if(e.target.matches(selector)) handler(e); });
};
// click will work for each selector
on('[type="button"], .test, #test','click', e => {
alert(e.target.innerHTML);
});
// click event will work for nested .test3 element only
on('.test3','click', e => {
alert(e.target.innerHTML);
},document.querySelector('.test2'));
<div id="test">
test
</div>
<div class="test">
test 1
</div>
<div class="test">
test 2
</div>
<button type="button">
go
</button>
<div class="test3">
test 3 outer
</div>
<div class="test2">
<div class="test3">
test 3 inner
</div>
test 2
</div>