1、场景一:给100个按钮添加点击事件

答:监听这 100 个按钮的祖先,等冒泡的时候判断 target 是不是这 100 个按钮中的一个
代码链接:http://js.jirengu.com/fowuj/1/edit?html,js,console,output

  1. div1.addEventListener('click',(e)=>{
  2. const t = e.target
  3. if(t.tagName.toLowerCase() === 'button'){
  4. console.log('button 被点击了')
  5. console.log('button的内容是'+t.textContent)
  6. //dataset获取以data开头的属性的值
  7. console.log('button data-id是'+t.dataset.id)
  8. }
  9. })
  1. <div id=div1>
  2. <span>span1</span>
  3. <button data-id="1">click1</button>
  4. <button data-id="2">click2</button>
  5. <button data-id="3">click3</button>
  6. <button>click4</button>
  7. <button>click5</button>
  8. //...
  9. </div>

image.png

冒泡允许我们利用事件委托——如果你想要在大量子元素中单击任何一个都可以运行一段代码,你可以将事件监听器设置在其父节点上,并让子节点上发生的事件冒泡到父节点上,而不是每个子节点单独设置事件监听器。

一个很好的例子是一系列列表项,如果你想让每个列表项被点击时弹出一条信息,你可以将click单击事件监听器设置在父元素<ul>上,这样事件就会从列表项冒泡到其父元素<ul>上。
代码链接:http://js.jirengu.com/zugik/3/edit

  1. <ul id="list">
  2. <li id="post-1">Item 1</li>
  3. <li id="post-2">Item 2</li>
  4. <li id="post-3">Item 3</li>
  5. <li id="post-4">Item 4</li>
  6. <li id="post-5">Item 5</li>
  7. <li id="post-6">Item 6</li>
  8. </ul>
  1. list.addEventListener("click", function(e) {
  2. const t = e.target
  3. if(t && t.nodeName == "LI") {
  4. console.log("List item ", t.id.replace("post-", ""), " was clicked!")
  5. }
  6. })

或者下面这种写法:

  1. list.addEventListener('click',(e)=>{
  2. const t = e.target
  3. if(t && t.tagName.toLowerCase() === 'li'){
  4. console.log(`List Item ${t.id.replace('post-','')} 被点击了`)
  5. }
  6. })

2、场景二:你要监听目前不存在的元素的点击事件,咋办???

答:监听祖先,等点击的时候,看看是不是我想要的监听的元素即可
代码链接:http://js.jirengu.com/gunov/1/edit?html,js,console,output

  1. <div id=div1>
  2. </div>
  1. //1秒后,创建button,并添加到div中
  2. setTimeout(()=>{
  3. const button = document.createElement('button')
  4. button.textContent = 'click 1'
  5. div1.appendChild(button)
  6. },1000)
  7. //事件委托
  8. div1.addEventListener('click',(e)=>{
  9. const t = e.target
  10. if(t.tagName.toLowerCase() === 'button'){
  11. console.log('button被点击了')
  12. }
  13. })

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

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>JS Bin</title>
  6. </head>
  7. <body>
  8. <div id=div1>
  9. </div>
  10. </body>
  11. </html>
  1. setTimeout(()=>{
  2. const button = document.createElement('button')
  3. button.textContent = 'click 1'
  4. div1.appendChild(button)
  5. },1000)
  6. on('click','#div1','button',()=>{
  7. console.log('button 被点击了')
  8. })
  9. //element是被监听的祖先 selector是用户点击的元素
  10. function on(eventType,element,selector,fn){
  11. //如果它不是元素 我就去找这个元素
  12. if(!(element instanceof Element)){
  13. element = document.querySelector(element)
  14. }
  15. //监听这个祖先元素
  16. element.addEventListener(eventType,(e)=>{
  17. const t = e.target
  18. if( t.matches(selector) ){
  19. fn(e)
  20. }
  21. })
  22. }


  1. on: function(element, eventType, selector, fn) {
  2. element.addEventListener(eventType, e => {
  3. let el = e.target
  4. while (!el.matches(selector)) {
  5. if (element === el) {
  6. el = null
  7. break
  8. }
  9. el = el.parentNode
  10. }
  11. el && fn.call(el, e, el)
  12. })
  13. return element
  14. },

参考文章:
https://davidwalsh.name/event-delegate
MDN | 事件委托

3、JS支持事件吗?

答:支持,也不支持。本节课讲的DOM事件不属于JS的功能
术语:浏览器提供的DOM功能
JS只是调用了DOM提供的addEventListener而已

3.1 如何让JS支持事件??

请手写一个事件系统

4、轮子