正如某人(不幸)了解了更多jQuery
而非原始 javascript
的人,我现在正在花时间更换我的所有原始javascript
的代码。不,这不是必需的,但这对我来说是一种更容易学习的方式。我遇到的一个问题是将所有$(document).on
转换为原始javascript
。我的网站是一个“单页面应用程序”,我的大多数实际HTML
都在不同的文件中,这些文件是通过Ajax
请求调用的。所以,我的问题是,我如何寻找动态加载内容的event
?我假设我必须向他们添加onclick
个事件,但jQuery
如何在不需要onclick
event
的情况下做到这一点?
答案 0 :(得分:34)
本机API中的绑定处理程序是使用addEventListener()
完成的。
要模拟jQuery的事件委派,您可以相当轻松地创建一个使用.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
开始并遍历父项,直到它到达绑定元素。每次,它检查当前元素是否与选择器匹配,如果是,则调用处理程序。
所以你这样称呼它:
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>
这是为.matches()
添加更多支持的垫片。
if (!Element.prototype.matches) {
Element.prototype.matches =
Element.prototype.matchesSelector ||
Element.prototype.webkitMatchesSelector ||
Element.prototype.mozMatchesSelector ||
Element.prototype.msMatchesSelector ||
Element.prototype.oMatchesSelector ||
function(s) {
var matches = (this.document || this.ownerDocument).querySelectorAll(s),
i = matches.length;
while (--i >= 0 && matches.item(i) !== this) {}
return i > -1;
};
}
答案 1 :(得分:12)
这是与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。当然,随着选择器的改变,你的代码必须更多地参与其中
答案 2 :(得分:3)
在现代浏览器中,您可以使用https://pyautogui.readthedocs.io/en/latest/install.html来简化jQuery Element.closest()
方法的复制,并确保从目标元素的子元素捕获事件冒泡(其他实现忽略的细微差别) 。较早的浏览器(包括IE)将需要.on()
才能运行。
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>
答案 3 :(得分:0)
现代浏览器的另一种方法是:
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>
答案 4 :(得分:0)
我会提供对 fantastic accepted answer 的非常小的改进:
function add_event(el, name, callback, selector) {
if (selector === undefined) {
el.addEventListener(name, callback);
}
else {
el.addEventListener(name, function(event) {
var t = event.target;
while (t && t !== this) {
if (t.matches(selector)) {
callback.call(t, event);
}
t = t.parentNode;
}
});
}
}
通过切换最后 2 个参数,您可以在省略选择器时恢复默认的 addEventListener 行为。