Understanding of Event Delegation
event delegation
参考链接:https://learn.jquery.com/events/event-delegation,https://davidwalsh.name/event-delegate
当我们需要为一些节点绑定事件时,我们通常会这么做
<ul id ="test"> <li>1</li> <li>2</li> <li>3</li> <li>4</li> </ul> <script> $("#test li").on("click", function(event) {
event.proventDefalut(); console.log($(this).text()); }) </script>
于是,我们触发点击事件后,就会弹出对应的text值;
但是,后来我们发现需要添加新的li标签了
$("test").apend("<li>5</li>")
虽然我们在理想中认为新添加的元素也应该在被点击后能够输出它的text,然而现实很骨感,点击它并不会有什么事情发生,因为新添加元素并没有绑定到event handler;
现在我们需要理解一个概念,Event Propagation。
在我们点击了某个li标签,它的click事件会被触发,然后向上冒泡,直达dom tree的根节点(document root);本例中的示意图大致是这样的
li
ul
body
html
document root
这就意味着我每次点击一个小小的li标签,就相当于点击了整个文档。——这就是eventPropagation 或者称为 eventbubbling的概念;
在我们了解event bubble是如何作用之后,我们就可以实现一个代理事件delegated event
// Attach a delegated event handler $( "#test" ).on( "click", "a", function( event ) { event.preventDefault(); console.log( $( this ).text() ); });
我们现在在.on()函数的第二个参数添加了一个“a”,它是作为ul标签的子元素存在的。当我们点击到ul下的任意一个a标签(无论它是在点击事件绑定前就存在的还是后来创建的),它会触发event bubble,当事件冒泡到ul上时(即触发ul的点击事件),会执行我们为ul绑定的回调函数,然后阻止点击事件继续冒泡(避免影响到其他元素)。
至此,我们可以发现,我们不需要再为某个父元素下的每个子元素都绑定诸如click事件,而是去为该父元素绑定事件。这个就是事件代理,借助冒泡机制将子元素的事件放在父元素上托管。
JQuery中我们通过.on()的第二个参数来实现event delegation,现在我们看看原生JS的实现方式,区别主要体现在如何匹配到指定的子元素上。
document.getElementById("test").addEventListener("click", function(e) { // e.target is the clicked element! // If it was a list item if(e.target && e.target.nodeName == "LI") { // List item found! Output the ID! console.log("List item",e.target," was clicked!"); } });
//实现ul下li点击事件的代理。
一个div#test下有多个子节点,我们需要为a.classA的子元素绑定点击事件,实现方式如下:
// Get the parent DIV, add click listener... document.getElementById("test").addEventListener("click",function(e) { // e.target was the clicked element if (e.target && e.target.matches("a.classA")) { console.log("Anchor element clicked!"); } });
在上方实现匹配到我们所关心的带有classA的class名的元素还可以使用正则匹配的方式:
var re = new RegExp('\\b'+class+'\\b'); re.test(e.target.className);
re.test(e.target.className)会返回一个bool类型的变量,当匹配到我们关心的元素,返回true,否则返回false;