1. 程式人生 > 其它 >怎麼觸發子級的點選事件_JS的事件委託

怎麼觸發子級的點選事件_JS的事件委託

技術標籤:怎麼觸發子級的點選事件

引言:遇到下面應用場景,你要怎麼辦?

場景一:

我們要給100個按鈕新增點選事件,怎麼辦?
最笨的辦法:直接給100個按鈕都addEventListener
但是有了事件委託後:監聽這100個按鈕的祖先,等冒泡的時候,判斷target是不是這100個按鈕中的一個 就可以了

場景二:

我們要監聽目前不存在的元素的點選事件,咋辦?
有了事件委託:監聽祖先,等到冒泡時,判斷點選的元素是不是我想要監聽的元素就可以了。

事件委託這麼牛,那他到底是什麼,怎麼實現的呢?別急,往下看。。。

一、什麼是事件委託?有什麼好處?

事件委託是指利用冒泡原理,把事件加到父級上,觸發執行效果。

由於冒泡階段,瀏覽器從使用者點選的內容從下往上遍歷至 window,逐個觸發事件處理函式,

因此可以監聽一個祖先節點(例如爸爸節點、爺爺節點)來同時處理多個子節點的事件。

好處

  • 減少事件數量,提高效能。
  • 預測未來元素,新新增的元素仍然可以觸發該事件。

---聽起來不錯,拉出來看看?

---好的,展示!

程式碼一:“實現10(或者更多)個按鈕,繫結click事件,按下後能夠返回按的是第幾個”
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
  <div id="zxm">
    <button data-id='1'>click1</button>
    <button data-id='2'>click2</button>
    <button data-id='3'>click3</button>
    <button data-id='4'>click4</button>
    <button data-id='5'>click5</button>
    <button data-id='6'>click6</button>
    <button data-id='7'>click7</button>
    <button data-id='8'>click8</button>
    <button data-id='9'>click9</button>
    <button data-id='10'>click10</button>
  </div>

</body>
</html>

JS程式碼:

zxm.addEventListener('click',(e) =>{
  const t = e.target
  if(t.tagName.toLowerCase()==='button'){
    console.log('data-id 是'+ t.dataset.id)
}
})

輸出結果:

98328843040d39950ede9c86602bff13.png
程式碼二:監聽所有的li標籤,如果使用者點選li標籤,就console.log('使用者點選了Li標籤')
<ul id="test">
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
</ul>

JS程式碼:

// 監聽父元素 ul#test
test.addEventListener('click', (e)=> {
  //通過瀏覽器傳進來的e引數,找到當前點選元素
  const t = e.target 
  // 判斷當前元素是不是Li標籤
  if(t.matches('li') {
    console.log('使用者點選了li')
  }
})
實現思路就是:
首先監聽父元素,
然後根據瀏覽器傳進去的事件資訊,拿到當前點選元素,
再判斷當前點選元素是不是li元素, 如果是,就console.log('使用者點選Li標籤')

JS 實現封裝

on('click', '#test', 'li', ()=>{
    console.log('使用者點選了li')
})

function on(eventType, element, selector, fn) {
     // 先判斷是不是element, 
    //如果傳進來的是選擇器,不是element本身,就先變成element,
   // 因為只有element才能監聽事件
    if (!(element instanceof Element)) {
        element = document.querySelector(element)
    }
    element.addEventListener(eventType, (e)=>{
        let target = e.target
        if (target.matches(selector)) {
            fn(e)
        }
    })
}

完整展示

JS Bin​js.jirengu.com 7788d65dab39369ce61e19ed3bf5dd37.png

但是以上這種實現有一個小問題,那就是如果被點選元素有多個父元素怎麼辦?

<ul id="test">
    <li>
      <p>
        <span>1</span>
      </p>
    </li>
    <li>
      <p>
        <span>2</span>
      </p>
    </li>
    <li>
      <p>
        <span>3</span>
      </p>
    </li>
    <li>
      <p>
        <span>4</span>
      </p>
    </li>
  </ul>

JS程式碼

遞迴地向上多找幾層父節點,直到找到li標籤,
同時還必須限定,尋找的範圍不能超過 element,
拿上面的例子來說,不可以越過ul標籤,去找body標籤
on('click', '#test', 'li', ()=>{
    console.log('使用者點選了li')
})

function on(eventType, element, selector, fn) {
    if (!(element instanceof Element)) {
        element = document.querySelector(element)
    }
 
    element.addEventListener(eventType, (e)=>{
        let el = e.target
        
        // 如果匹配到了selector就跳出迴圈
        while(!el.matches(selector)){
            if (el === element){
                //已經找到了父元素,說明還沒找到,就設定為null
                el = null
                break
            }
            el = el.parentNode
           
        }
      
      	// 找到了el, 就呼叫函式
        el && fn.call(el, e, el) 
    })
   
    return element
}

完整展示:

JS Bin​js.jirengu.com 7788d65dab39369ce61e19ed3bf5dd37.png

二、再來回顧一下:

事件委託是指利用冒泡原理,把事件加到父級上,觸發執行效果。

由於冒泡階段,瀏覽器從使用者點選的內容從下往上遍歷至 window,逐個觸發事件處理函式,

因此可以監聽一個祖先節點(例如爸爸節點、爺爺節點)來同時處理多個子節點的事件。

好處

  • 減少事件數量,提高效能。
  • 預測未來元素,新新增的元素仍然可以觸發該事件。