日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

移除元素所有事件监听_DOM 事件模型或 DOM 事件机制

發(fā)布時(shí)間:2025/3/11 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 移除元素所有事件监听_DOM 事件模型或 DOM 事件机制 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

DOM 事件模型

DOM 的事件操作(監(jiān)聽和觸發(fā)),都定義在EventTarget接口。所有節(jié)點(diǎn)對(duì)象都部署了這個(gè)接口,其他一些需要事件通信的瀏覽器內(nèi)置對(duì)象(比如,XMLHttpRequest、AudioNode、AudioContext)也部署了這個(gè)接口。

該接口主要提供三個(gè)實(shí)例方法。

  • addEventListener:綁定事件的監(jiān)聽函數(shù)
  • removeEventListener:移除事件的監(jiān)聽函數(shù)
  • dispatchEvent:觸發(fā)事件

事件模型

一個(gè)事件發(fā)生后,會(huì)在子元素及父元素之間進(jìn)行傳播(propagation),這種傳播分為三個(gè)階段。

(這種三階段的傳播模型,使得同一個(gè)事件會(huì)在多個(gè)節(jié)點(diǎn)上觸發(fā)。)

  • 由外向內(nèi)找監(jiān)聽函數(shù)就是事件捕獲
  • 在目標(biāo)節(jié)點(diǎn)觸發(fā)事件
  • 由內(nèi)而外找監(jiān)聽函數(shù)就是事件冒泡
  • 通俗一點(diǎn)來說就是一個(gè)事件被觸發(fā)時(shí),瀏覽器會(huì)自動(dòng)從用戶操作標(biāo)簽外的最上級(jí)標(biāo)簽逐漸向里檢查是否有相同事件,如果有則觸發(fā),如果沒有則繼續(xù)向下檢查知道用戶操作的標(biāo)簽,這過程稱為捕獲,此時(shí)瀏覽器會(huì)繼續(xù)由用戶操作標(biāo)簽繼續(xù)向是上級(jí)標(biāo)簽檢查,如果有相同事件則觸發(fā),如果沒有則繼續(xù)向上檢查直到最上級(jí)元素為止,此過程稱為冒泡。(有監(jiān)聽函數(shù)就執(zhí)行,并提供事件信息,沒有就跳過)

    事件傳播的最上層對(duì)象是window,上例的事件傳播順序,在捕獲階段依次為window、document、html、body、父節(jié)點(diǎn)、目標(biāo)節(jié)點(diǎn),在冒泡階段依次為目標(biāo)節(jié)點(diǎn)、父節(jié)點(diǎn)、body、html、document、window。

    DOM事件傳播的三個(gè)階段:捕獲階段,目標(biāo)階段,冒泡階段

    點(diǎn)擊事件

    代碼:

    <div class="grandfather"><div class="father"><div class="son"></div>word</div> </div>

    即.grandfather>.father>.son

    給三個(gè)div分別添加事件的監(jiān)聽fnYe/fnBa/fnEr

    提問1:點(diǎn)擊了誰?

    點(diǎn)擊文字,算不算點(diǎn)擊兒子?

    點(diǎn)擊文字,算不算點(diǎn)擊爸爸?

    點(diǎn)擊文字,算不算點(diǎn)擊爺爺?

    答案:都算

    提問2:調(diào)用循序

    點(diǎn)擊文字,最先調(diào)用fnYe/fnBa/fnEr中的那一個(gè)函數(shù)?

    答案:都行

    IE5認(rèn)為先調(diào)用fnEr,網(wǎng)景認(rèn)為先調(diào)用fnYe,最后遇到了W3C

    2002年,w3c發(fā)布標(biāo)準(zhǔn)
    文檔名為DOM Level 2 Events Specification
    規(guī)定瀏覽器應(yīng)該同時(shí)支持兩種調(diào)用順序
    首先按照grandfather->father->son
    然后按照son->father->grandfather

    術(shù)語:

    從外向內(nèi)找監(jiān)聽函數(shù),叫做事件捕捉
    從內(nèi)向外找監(jiān)聽函數(shù),叫做事件冒泡
    那豈不是fnYe/fnBa/fnEr都調(diào)用兩次,非也!
    開發(fā)者可以自己決定把fnYe放在捕捉階段還是放在冒泡階段

    addEventListener事件綁定API

    IE5*:baba.attachEvent('onclick',fn)//冒泡

    網(wǎng)景:baba.addEventListener('click',fn)//捕獲

    W3C:baba.addEventListener('click',fn,bool)

    如果bool不傳或?yàn)閒alsy

    就讓fn走冒泡,即當(dāng)瀏覽器在冒泡階段發(fā)現(xiàn)baba有fn監(jiān)聽函數(shù),就會(huì)調(diào)用fn,并提供時(shí)間信息。

    如果bool為true

    就讓fn走捕獲,即當(dāng)瀏覽器在捕獲階段發(fā)現(xiàn)baba有fn監(jiān)聽函數(shù),就會(huì)調(diào)用fn,并且提供事件信息。

    代碼演示:

    <!DOCTYPE html> <html> <head><meta charset="utf-8"><title>JS Bin</title> </head> <body> <div class="level1 x"><div class="level2 x"><div class="level3 x"><div class="level4 x"><div class="level5 x"><div class="level6 x"><div class="level7 x"></div></div></div></div></div></div> </div></body> </html>

    CSS:

    * {box-sizing: border-box; } div[class^=level] {border: 1px solid;border-radius: 50%;display: inline-flex; } .level1 {padding: 10px;background: purple; } .level2 {padding: 10px;background: blue; } .level3 {padding: 10px;background: cyan; } .level4 {padding: 10px;background: green; } .level5 {padding: 10px;background: yellow; } .level6 {padding: 10px;background: orange; } .level7 {width: 50px;height: 50px;border: 1px solid;background: red;border-radius: 50%; } .x{background: transparent;//把元素的變?yōu)橥该?}

    Javascript代碼:

    const level1 = document.querySelector('.level1') const level2 = document.querySelector('.level2') const level3 = document.querySelector('.level3') const level4 = document.querySelector('.level4') const level5 = document.querySelector('.level5') const level6 = document.querySelector('.level6') const level7 = document.querySelector('.level7')let n = 1level1.addEventListener('click', (e)=>{const t = e.currentTarget//e只有在點(diǎn)擊得一瞬間才會(huì)出現(xiàn),所以要用t來記錄一下。setTimeout(()=>{ t.classList.remove('x')},n*1000)n+=1//因?yàn)槿绻總€(gè)時(shí)間都為1000那么就相當(dāng)于在8點(diǎn)同時(shí)設(shè)置很多的鬧鐘,。知識(shí) }) level2.addEventListener('click', (e)=>{const t = e.currentTargetsetTimeout(()=>{ t.classList.remove('x')},n*1000)n+=1 }) level3.addEventListener('click', (e)=>{const t = e.currentTargetsetTimeout(()=>{ t.classList.remove('x')},n*1000)n+=1 }) level4.addEventListener('click', (e)=>{const t = e.currentTargetsetTimeout(()=>{ t.classList.remove('x')},n*1000)n+=1 }) level5.addEventListener('click', (e)=>{const t = e.currentTargetsetTimeout(()=>{ t.classList.remove('x')},n*1000)n+=1 }) level6.addEventListener('click', (e)=>{const t = e.currentTargetsetTimeout(()=>{ t.classList.remove('x')},n*1000)n+=1 }) level7.addEventListener('click', (e)=>{const t = e.currentTargetsetTimeout(()=>{ t.classList.remove('x')},n*1000)n+=1 })

    簡化:

    const level1 = document.querySelector('.level1') const level2 = document.querySelector('.level2') const level3 = document.querySelector('.level3') const level4 = document.querySelector('.level4') const level5 = document.querySelector('.level5') const level6 = document.querySelector('.level6') const level7 = document.querySelector('.level7')let n = 1const fm = (e)=>{const t = e.currentTargetsetTimeout(()=>{ t.classList.remove('x')},n*1000)n+=1 }const fa = (e)=>{const t =e.currentTargetsetTimeout(()=>{t.classList.add('x')},n*1000)n+=1}level1.addEventListener('click',fm,true) level1.addEventListener('click',fa) level2.addEventListener('click',fm,true) level2.addEventListener('click',fa) level3.addEventListener('click',fm,true) level3.addEventListener('click',fa) level4.addEventListener('click',fm,true) level4.addEventListener('click',fa) level5.addEventListener('click',fm,true) level5.addEventListener('click',fa) level6.addEventListener('click',fm,true) level6.addEventListener('click',fa) level7.addEventListener('click',fm,true) level7.addEventListener('click',fa)

    知識(shí)復(fù)習(xí):

    classList:

    定義和用法

    classList 屬性返回元素的類名,作為 DOMTokenList 對(duì)象。

    該屬性用于在元素中添加,移除及切換 CSS 類。

    classList 屬性是只讀的,但你可以使用 add() 和 remove() 方法修改它。

    HTML DOM classList 屬性?www.runoob.com

    currentTarget 事件屬性

    定義和用法

    currentTarget 事件屬性返回其監(jiān)聽器觸發(fā)事件的節(jié)點(diǎn),即當(dāng)前處理該事件的元素、文檔或窗口。
    在捕獲和起泡階段,該屬性是非常有用的,因?yàn)樵谶@兩個(gè)節(jié)點(diǎn),它不同于 target 屬性。

    currentTarget ê??tê?D??www.w3school.com.cn

    總結(jié):

    兩個(gè)疑問:

    兒子被點(diǎn)擊,算不算點(diǎn)擊老子?

    那么先調(diào)用老子得函數(shù)還是先調(diào)用兒子的函數(shù)?

    捕獲冒泡

    捕獲說先調(diào)用爸爸的監(jiān)聽函數(shù)

    冒泡說先調(diào)用兒子的監(jiān)聽函數(shù)

    W3C時(shí)間模型

    先捕獲(先爸爸=>兒子)再冒泡(再兒子=>爸爸)

    注意e對(duì)象被傳給所有的監(jiān)聽函數(shù)

    事件結(jié)束后,e對(duì)象就不存在了

    target v.s. currentTarget的區(qū)別

    區(qū)別:

    e.target - 用戶操作的元素
    e.currentTarget-程序員監(jiān)聽的元素
    this是e.currentTarget,我個(gè)人不推薦使用它

    舉例:

    div>span{文字},用戶點(diǎn)擊文字
    e.target就是span
    e.currentTarget就是div

    一個(gè)特例

    背景:

    只有一個(gè)div被監(jiān)聽(不考慮父子同時(shí)被監(jiān)聽)

    fn分別再捕獲階段和冒泡階段監(jiān)聽click事件

    用戶點(diǎn)擊的元素就是開發(fā)者監(jiān)聽的

    代碼:

    div.addEventListenter('click',f1)

    div.addEventListenter('click',f2,true)

    請(qǐng)問,f1先執(zhí)行還是f2先執(zhí)行?

    如果把兩個(gè)調(diào)換位置?

    總結(jié):誰先監(jiān)聽誰先執(zhí)行。

    level7.addEventListener('click',()=>{console.log(2) },true)//捕獲 level7.addEventListener('click',()=>{console.log(1) })//冒泡

    e.stopPropagation():取消冒泡

    e.stopPropagation()可打斷冒泡,瀏覽器不再向上走

    一般用于封裝某些獨(dú)立組件

    注意:捕獲不可以取消但是冒泡可以

    不可以取消冒泡

    有些事件不可以取消冒泡

    可以查閱MDN英文版冒泡

    比如scroll:

    Bubbles:冒泡

    Cancelable:是否取消冒泡

    如何禁用滾動(dòng)

    取消特定元素的wheel和touchstart的默認(rèn)動(dòng)作

    JS Bin?js.jirengu.com

    瀏覽器自帶事件

    來自MDN:

    事件參考?developer.mozilla.org

    自定義事件:代碼

    JS Bin?js.jirengu.com

    事件委托:

    我委托一個(gè)元素幫我監(jiān)聽我本該監(jiān)聽的東西,比如onclick

    場景1:

    要給100個(gè)按鈕添加點(diǎn)擊事件,咋辦?

    答:監(jiān)聽這個(gè)100個(gè)按鈕的祖先,等冒泡的時(shí)候判斷target是不是這100個(gè)按鈕中的一個(gè)

    代碼:

    JS Bin?js.jirengu.com

    場景2:

    你要監(jiān)聽目前不存在的元素的點(diǎn)擊事件?

    答:監(jiān)聽祖先,等點(diǎn)擊的時(shí)候看看是不是監(jiān)聽的元素即可。

    優(yōu)點(diǎn):省監(jiān)聽數(shù)(內(nèi)存),可以動(dòng)態(tài)監(jiān)聽元素

    代碼:

    JS Bin?js.jirengu.com

    封裝一個(gè)事件委托

    只要實(shí)行一個(gè)函數(shù)就可以實(shí)現(xiàn)事件委托

    要求:

    寫出這樣一個(gè)函數(shù)on('click','#testDiv','li',fn)

    當(dāng)用戶點(diǎn)擊#testDiv里面的li元素時(shí),調(diào)用fn函數(shù)

    要求用到事件委托

    答案1:判斷target是否匹配'li'

    答案2:target/target的爸爸/target的爺爺

    代碼:

    JS Bin?js.jirengu.com

    錯(cuò)的但是面試可以用:

    答:給一個(gè)元素加一個(gè)監(jiān)聽,看當(dāng)前的target是否滿足監(jiān)聽函數(shù)(函數(shù)2)中函數(shù)2的條件如果滿足調(diào)用,不滿足放過。但是是錯(cuò)的!

    代碼:

    setTimeout(()=>{const button = document.createElement('button')const span = document.createElement('span')span.textContent='click 1'button.appendChild(span)div1.appendChild(button) },1000)on('click','#div1','button',()=>{//'#div'是選擇器不是元素console.log('button 被點(diǎn)擊啦') }) function on(eventType,element,selector,fn){if(!(element instanceof Element)){element = document.querySelector(element)}element.addEventListener(eventType,(e)=>{const t= e.target//被點(diǎn)擊的元素是span不是button啦if(t.matches(selector)){//matches用來判斷一個(gè)元素是否匹配一個(gè)選擇器,selector是不是一個(gè)選擇器 span不匹配buttonfn(e)} }) }

    總結(jié)

    以上是生活随笔為你收集整理的移除元素所有事件监听_DOM 事件模型或 DOM 事件机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。