1、场景一:给100个按钮添加点击事件
答:监听这 100 个按钮的祖先,等冒泡的时候判断 target 是不是这 100 个按钮中的一个
代码链接:http://js.jirengu.com/fowuj/1/edit?html,js,console,output
div1.addEventListener('click',(e)=>{const t = e.targetif(t.tagName.toLowerCase() === 'button'){console.log('button 被点击了')console.log('button的内容是'+t.textContent)//dataset获取以data开头的属性的值console.log('button data-id是'+t.dataset.id)}})
<div id=div1><span>span1</span><button data-id="1">click1</button><button data-id="2">click2</button><button data-id="3">click3</button><button>click4</button><button>click5</button>//...</div>

冒泡允许我们利用事件委托——如果你想要在大量子元素中单击任何一个都可以运行一段代码,你可以将事件监听器设置在其父节点上,并让子节点上发生的事件冒泡到父节点上,而不是每个子节点单独设置事件监听器。
一个很好的例子是一系列列表项,如果你想让每个列表项被点击时弹出一条信息,你可以将click单击事件监听器设置在父元素<ul>上,这样事件就会从列表项冒泡到其父元素<ul>上。
代码链接:http://js.jirengu.com/zugik/3/edit
<ul id="list"><li id="post-1">Item 1</li><li id="post-2">Item 2</li><li id="post-3">Item 3</li><li id="post-4">Item 4</li><li id="post-5">Item 5</li><li id="post-6">Item 6</li></ul>
list.addEventListener("click", function(e) {const t = e.targetif(t && t.nodeName == "LI") {console.log("List item ", t.id.replace("post-", ""), " was clicked!")}})
或者下面这种写法:
list.addEventListener('click',(e)=>{const t = e.targetif(t && t.tagName.toLowerCase() === 'li'){console.log(`List Item ${t.id.replace('post-','')} 被点击了`)}})
2、场景二:你要监听目前不存在的元素的点击事件,咋办???
答:监听祖先,等点击的时候,看看是不是我想要的监听的元素即可
代码链接:http://js.jirengu.com/gunov/1/edit?html,js,console,output
<div id=div1></div>
//1秒后,创建button,并添加到div中setTimeout(()=>{const button = document.createElement('button')button.textContent = 'click 1'div1.appendChild(button)},1000)//事件委托div1.addEventListener('click',(e)=>{const t = e.targetif(t.tagName.toLowerCase() === 'button'){console.log('button被点击了')}})
3、优点:
- 省监听数(内存)
- 可以监听动态元素(要监听的元素还没创建)
2、封装事件委托
2.1 要求:
写出这样一个函数:on(‘click’,’#div1’,’button’,fn)
当用户点击#div1里面的button元素时,调用fn函数
要求用到事件委托2.2 答案1
判断target是否匹配’li’2.3 答案2
递归判断target/target的爸爸/target的爷爷
代码链接:http://js.jirengu.com/zohit/1/edit?html,js,console,output
或者:http://js.jirengu.com/nutow/1/edit?html,js,console,output
<!DOCTYPE html><html><head><meta charset="utf-8"><title>JS Bin</title></head><body><div id=div1></div></body></html>
setTimeout(()=>{const button = document.createElement('button')button.textContent = 'click 1'div1.appendChild(button)},1000)on('click','#div1','button',()=>{console.log('button 被点击了')})//element是被监听的祖先 selector是用户点击的元素function on(eventType,element,selector,fn){//如果它不是元素 我就去找这个元素if(!(element instanceof Element)){element = document.querySelector(element)}//监听这个祖先元素element.addEventListener(eventType,(e)=>{const t = e.targetif( t.matches(selector) ){fn(e)}})}
on: function(element, eventType, selector, fn) {element.addEventListener(eventType, e => {let el = e.targetwhile (!el.matches(selector)) {if (element === el) {el = nullbreak}el = el.parentNode}el && fn.call(el, e, el)})return element},
参考文章:
https://davidwalsh.name/event-delegate
MDN | 事件委托
3、JS支持事件吗?
答:支持,也不支持。本节课讲的DOM事件不属于JS的功能
术语:浏览器提供的DOM功能
JS只是调用了DOM提供的addEventListener而已
