实时绑定事件处理程序
为现在、将来和给定选择器匹配的所有元素附加事件处理程序
为了在匹配的选择器的任何将来元素上自动绑定事件处理程序,我们使用了一个小技巧: 实际上,将事件处理程序绑定到文档而不是绑定到元素的事件。 事件在树上冒出气泡,当触发文档的事件处理程序时,我们检查事件的来源,看它是否与实时绑定选择器匹配:
// helper for enabling IE 8 event bindings
function addEvent(el, type, handler) {
if (el.attachEvent) el.attachEvent('on'+type, handler); else el.addEventListener(type, handler);
}
// live binding helper
function live(selector, event, callback, context) {
addEvent(context || document, event, function(e) {
var found, el = e.target || e.srcElement;
while (el && !(found = el.id == selector)) el = el.parentElement;
if (found) callback.call(el, e);
});
}
// example use
live('foo', 'click', function(){ console.log('Clicked #foo'); });
注意: 实际上,这不能完全替代jQuery的$.live()
方法:在本示例中live()
函数专门检查被单击元素的ID是否匹配“foo”。 测试其他选择器需要修改
while
语句el.id == elementId
。 您可以选择检查类名称或任何其他属性/值。
当需要任意匹配的选择器时,请使用以下实时绑定代码。 虽然有点慢,但是可以达到和jQuery的$.live()
方法一样的灵活性:
function live(selector, event, callback, context) {
addEvent(context || document, event, function(e) {
var qs = (context || document).querySelectorAll(selector);
if (qs) {
var el = e.target || e.srcElement, index = -1;
while (el && ((index = Array.prototype.indexOf.call(qs, el)) === -1)) el = el.parentElement;
if (index > -1) callback.call(el, e);
}
});
}
最后,这是一个性能优化的版本,该版本将现代DOM4方法与针对旧版浏览器的polyfill结合使用:
// matches polyfill
this.Element && function(ElementPrototype) {
ElementPrototype.matches = ElementPrototype.matches ||
ElementPrototype.matchesSelector ||
ElementPrototype.webkitMatchesSelector ||
ElementPrototype.msMatchesSelector ||
function(selector) {
var node = this, nodes = (node.parentNode || node.document).querySelectorAll(selector), i = -1;
while (nodes[++i] && nodes[i] != node);
return !!nodes[i];
}
}(Element.prototype);
// live binding helper using matchesSelector
function live(selector, event, callback, context) {
addEvent(context || document, event, function(e) {
var found, el = e.target || e.srcElement;
while (el && el.matches && el !== context && !(found = el.matches(selector))) el = el.parentElement;
if (found) callback.call(el, e);
});
}
通过使用适当的closet()
方法而不是while语句,可以进一步优化此版本。