最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript 事件捕獲冒泡與捕獲詳情

 更新時(shí)間:2021年11月10日 08:49:19   作者:四冥  
這篇文章主要介紹了JavaScript事件捕獲冒泡與捕獲,文章主要圍繞JavaScript事件捕獲冒泡與捕獲展開(kāi)詳細(xì)內(nèi)容,需要的朋友可以參考一下,希望對(duì)你有所幫助

一、事件流

JavaScript中,事件流指的是DOM事件流。

1、概念

事件的傳播過(guò)程即DOM事件流。
事件對(duì)象在 DOM 中的傳播過(guò)程,被稱為“事件流”。
舉個(gè)例子:開(kāi)電腦這個(gè)事,首先你是不是得先找到你的電腦,然后找到你的開(kāi)機(jī)鍵,最后用手按下開(kāi)機(jī)鍵。完成開(kāi)電腦這個(gè)事件。這整個(gè)流程叫做事件流。

2、DOM事件流

DOM事件,也是有一個(gè)流程的。從事件觸發(fā)開(kāi)始到事件響應(yīng)是有三個(gè)階段。

  • 事件捕獲階段
  • 處于目標(biāo)階段
  • 事件冒泡階段

上面例子中,開(kāi)電腦這個(gè)事件的過(guò)程就像JavaScript中的事件流,找開(kāi)機(jī)鍵這個(gè)過(guò)程就是 事件捕獲 的過(guò)程,你找到開(kāi)機(jī)鍵后,然后用手按開(kāi)機(jī)鍵,這個(gè)選擇用手去按的過(guò)程就是 處于目標(biāo)階段 按下開(kāi)機(jī)按鈕,電腦開(kāi)始開(kāi)機(jī)這也就是 事件的冒泡。 順序?yàn)橄炔东@再冒泡。

了解了事件源,讓我們看看它的三個(gè)過(guò)程吧!

事件捕獲:

注:由于事件捕獲不被舊版本瀏覽器(IE8 及以下)支持,因此實(shí)際中通常在冒泡階段觸發(fā)事件處理程序。

事件捕獲處于事件流的第一步,
DOM事件觸發(fā)時(shí)(被觸發(fā)DOM事件的這個(gè)元素被叫作事件源),瀏覽器會(huì)從根節(jié)點(diǎn)開(kāi)始 由外到內(nèi) 進(jìn)行事件傳播。即事件從文檔的根節(jié)點(diǎn)流向目標(biāo)對(duì)象節(jié)點(diǎn)。途中經(jīng)過(guò)各個(gè)層次的DOM節(jié)點(diǎn),最終到目標(biāo)節(jié)點(diǎn),完成事件捕獲。

目標(biāo)階段:

當(dāng)事件到達(dá)目標(biāo)節(jié)點(diǎn)的,事件就進(jìn)入了目標(biāo)階段。事件在目標(biāo)節(jié)點(diǎn)上被觸發(fā)。
就是事件傳播到觸發(fā)事件的最底層元素上。

事件冒泡:

事件冒泡與事件捕獲順序相反。事件捕獲的順序是從外到內(nèi),事件冒泡是從內(nèi)到外。
當(dāng)事件傳播到了目標(biāo)階段后,處于目標(biāo)階段的元素就會(huì)將接收到的時(shí)間向上傳播,就是順著事件捕獲的路徑,反著傳播一次,逐級(jí)的向上傳播到該元素的祖先元素。直到window對(duì)象。

看一個(gè)例子,點(diǎn)擊 box3 會(huì)將 box2 與 box1 的點(diǎn)擊事件觸發(fā)。

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>JavaScript 事件冒泡</title>
</head>
<style type="text/css">
    #box1 { background: blueviolet;}
    #box2 {background: aquamarine;}
    #box3 {background: tomato;}
    div { padding: 40px; margin: auto;}
</style>

<body>
    <div id="box1">
        <div id="box2">
            <div id="box3"></div>
        </div>
    </div>
    <script>
        window.onload = function () {
            const box1 = document.getElementById('box1')
            const box2 = document.getElementById('box2')
            const box3 = document.getElementById('box3')
            box1.onclick = sayBox1;
            box2.onclick = sayBox2;
            box3.onclick = sayBox3;
            function sayBox3() {
                console.log('你點(diǎn)了最里面的box');
            }
            function sayBox2() {
                console.log('你點(diǎn)了最中間的box');
            }
            function sayBox1() {
                console.log('你點(diǎn)了最外面的box');
            }
        }
    </script>
</body>

</html>


這個(gè)時(shí)候 click 捕獲的傳播順序?yàn)椋?br /> window -> document -> <html> -> <body> -> <div #box1> -> <div #box2> -> <div #box3>
這個(gè)時(shí)候 click 冒泡的傳播順序?yàn)椋?br /> <div #box3> -> <div #box2> -> <div #box1> -> <body> -> <html> -> document -> window

現(xiàn)代瀏覽器都是從 window 對(duì)象開(kāi)始捕獲事件的,冒泡最后一站也是 window 對(duì)象。而 IE8 及以下瀏覽器,只會(huì)冒泡到 document 對(duì)象。
事件冒泡:是由元素的 HTML 結(jié)構(gòu)決定,而不是由元素在頁(yè)面中的位置決定,所以即便使用定位或浮動(dòng)使元素脫離父元素的范圍,單擊元素時(shí),其依然存在冒泡現(xiàn)象。

現(xiàn)在我們知道了事件流的三個(gè)階段后,那我們可以利用這個(gè)特性做什么呢?

二、事件委托

設(shè)想這樣一個(gè)場(chǎng)景,當(dāng)你有一堆的<li>標(biāo)簽在一個(gè)<ul>標(biāo)簽下,需要給所有的<li>標(biāo)簽綁定onclick事件,這個(gè)問(wèn)題我們可以用循環(huán)解決,但還有沒(méi)有更簡(jiǎn)便的方式呢?
我們可以給這些<li>共同的父元素<ul>添加onclick事件,那么里面的任何一個(gè)<li>標(biāo)簽觸發(fā)onclick事件時(shí),都會(huì)通過(guò)冒泡機(jī)制,將onclick事件傳播到<ul>上,進(jìn)行處理。這個(gè)行為叫做事件委托, <li>利用事件冒泡將事件委托到<ul>上。
也可以利用事件捕獲進(jìn)行事件委托。用法是一樣的,只是順序反了。

  <ul id="myUl">
    <li>item 1</li>
    <li>item 2</li>
    <li>item 3</li>
    ...
  </ul>


可能還是有點(diǎn)不好理解,簡(jiǎn)單來(lái)說(shuō),就是利用事件冒泡,將某個(gè)元素上的事件委托給他的父級(jí)。

舉個(gè)生活中的例子,雙十一快遞到了,需要快遞小哥送快遞一般是挨家挨戶送貨上門,這樣效率慢,小哥想了個(gè)辦法,把一個(gè)小區(qū)的快遞都放在小區(qū)里面的快遞驛站,進(jìn)行送快遞的事件委托,小區(qū)的收件人能通過(guò)取件碼去快遞驛站領(lǐng)取到自己的快遞。
在這里,快遞小哥送快遞就是一個(gè)事件,收件人就是響應(yīng)事件的元素,驛站就相當(dāng)于代理元素,收件人憑著收獲碼去驛站里面領(lǐng)快遞就是事件執(zhí)行中,代理元素判斷當(dāng)前響應(yīng)的事件匹配該觸發(fā)的具體事件。

可是這樣做有什么好處呢?

1、事件委托的優(yōu)點(diǎn)

事件委托有兩個(gè)好處

  • 減少內(nèi)存消耗
  • 動(dòng)態(tài)綁定事件

減少內(nèi)存消耗,優(yōu)化頁(yè)面性能

JavaScript中,每個(gè)事件處理程序都是對(duì)象,是對(duì)象就會(huì)占用頁(yè)面內(nèi)存,內(nèi)存中的對(duì)象越多,頁(yè)面的性能當(dāng)然越差,而且DOM的操作是會(huì)導(dǎo)致瀏覽器對(duì)頁(yè)面進(jìn)行重排和重繪(這個(gè)不清楚的話,小伙伴可以了解頁(yè)面的渲染過(guò)程),過(guò)多的DOM操作會(huì)影響頁(yè)面的性能。性能優(yōu)化主要思想之一就是為了最小化的重排和重繪也就是減少DOM操作。

在上面給<li>標(biāo)簽綁定onclick事件的例子中,使用事件委托就可以不用給每一個(gè)<li>綁定一個(gè)函數(shù),只需要給<ul>綁定一次就可以了,當(dāng)li的數(shù)量很多時(shí),無(wú)疑能減少大量的內(nèi)存消耗,節(jié)約效率。

動(dòng)態(tài)綁定事件:

如果子元素不確定或者動(dòng)態(tài)生成,可以通過(guò)監(jiān)聽(tīng)父元素來(lái)取代監(jiān)聽(tīng)子元素。
還是上面在<li>標(biāo)簽綁定onclick事件的例子中, 很多時(shí)候我們的這些<li>標(biāo)簽的數(shù)量并不是固定的,會(huì)根據(jù)用戶的操作對(duì)一些<li>標(biāo)簽進(jìn)行增刪操作。在每次增加或刪除標(biāo)簽都要重新對(duì)新增或刪除元素綁定或解綁對(duì)應(yīng)事件。

可以使用事件委托就可以不用給每一個(gè)<li>都要操作一遍,只需要給<ul>綁定一次就可以了,因?yàn)槭录墙壎ㄔ?code><ul>上的, <li>元素是影響不到<ul>的 ,執(zhí)行到<li>元素是在真正響應(yīng)執(zhí)行事件函數(shù)的過(guò)程中去匹配的,所以使用事件委托在動(dòng)態(tài)綁定事件的情況下是可以減少很多重復(fù)工作的。

我們知道了事件委托的優(yōu)點(diǎn),那么該如何使用呢?

2、事件委托的使用

事件委托的使用需要用的addEventListener()方法,事件監(jiān)聽(tīng)。
方法將指定的監(jiān)聽(tīng)器注冊(cè)到調(diào)用該函數(shù)的對(duì)象上,當(dāng)該對(duì)象觸發(fā)指定的事件時(shí),指定的回調(diào)函數(shù)就會(huì)被執(zhí)行。

用法:

element.addEventListener(eventType, function, useCapture);


參數(shù) 必/選填 描述
eventType 必填 指定事件的類型。
function 必填 指定事件觸發(fā)后的回調(diào)函數(shù)。
useCapture 選填 指定事件是在捕獲階段執(zhí)行還是在冒泡階段執(zhí)行。

第三個(gè)參數(shù) useCapture 是個(gè)布爾類型,默認(rèn)值為false

  • true - 表示事件在捕獲階段執(zhí)行執(zhí)行
  • false- 表示事件在冒泡階段執(zhí)行執(zhí)行

看下面例子:

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>JavaScript 事件委托</title>
</head>

<body>

  <ul>
    <li>item 1</li>
    <li>item 2</li>
    <li>item 3</li>
    <li>item 4</li>
  </ul>

  <script>
    const myUl = document.getElementsByTagName("ul")[0];

    myUl.addEventListener("click", myUlFn);

    function myUlFn(e) {
      if (e.target.tagName.toLowerCase() === 'li') { // 判斷是否為所需要點(diǎn)擊的元素
        console.log(`您點(diǎn)擊了${e.target.innerText}`);
      }
    }

  </script>
</body>

</html>

注意:這是一般的事件委托方法,但是這種寫法有問(wèn)題,就是當(dāng)_<li>_中還有子元素時(shí),點(diǎn)擊這個(gè)子元素就不會(huì)進(jìn)行觸發(fā)事件。這個(gè)問(wèn)題是一個(gè)坑。

事件冒泡有時(shí)候確實(shí)很有用,但是有時(shí)候也討人煩,當(dāng)你不需要它的時(shí)候能不能取消掉呢?

三、禁止事件冒泡與捕獲

注意:并不是所有事件都會(huì)冒泡,比如focus,blur,change,submit,reset,select等。

禁止冒泡和捕獲可以用到方法stopPropagation()。
stopPropagation()起到阻止捕獲和冒泡階段中當(dāng)前事件的進(jìn)一步傳播。
這是阻止事件的冒泡方法,進(jìn)行冒泡,但是默認(rèn)事件任然會(huì)執(zhí)行,當(dāng)你調(diào)用了這個(gè)方法后。
如果點(diǎn)擊一個(gè)a標(biāo)簽,這個(gè)a標(biāo)簽會(huì)進(jìn)行跳轉(zhuǎn)。

使用起來(lái)也很簡(jiǎn)單,沒(méi)有返回值也沒(méi)有參數(shù)。

event.stopPropagation();


請(qǐng)看下面例子,這個(gè)例子實(shí)在上文事件冒泡例子基礎(chǔ)上稍加修改得到的

    <div id="box1">
        <div id="box2">
            <div id="box3"></div>
        </div>
    </div>
    <script>
        const box1 = document.getElementById('box1')
        const box2 = document.getElementById('box2')
        const box3 = document.getElementById('box3')
        box1.onclick = sayBox1;
        box2.onclick = sayBox2;
        box3.onclick = sayBox3;
        function sayBox3() {
            console.log('你點(diǎn)了最里面的box');
        }
        function sayBox2(e) {
            console.log('你點(diǎn)了最中間的box');
            e.stopPropagation(); //禁止事件捕獲和冒泡
        }
        function sayBox1() {
            console.log('你點(diǎn)了最外面的box');
        }
    </script>

當(dāng)事件冒泡到box2時(shí)調(diào)用了在函數(shù)sayBox2,調(diào)用了e.stopPropagation(); 就停止冒泡了。

到此這篇關(guān)于JavaScript 事件捕獲冒泡與捕獲詳情的文章就介紹到這了,更多相關(guān)JavaScript事件捕獲冒泡與捕獲內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

四、參考文獻(xiàn)

MDN中文版 https://developer.mozilla.org/zh-CN/
知乎 https://zhuanlan.zhihu.com/p/26536815

相關(guān)文章

最新評(píng)論

城口县| 景宁| 安丘市| 铜川市| 宁乡县| 天气| 梅州市| 泽普县| 安徽省| 榆社县| 成武县| 清新县| 弥渡县| 玛纳斯县| 忻城县| 雅江县| 肃北| 朝阳县| 金山区| 河北省| 通榆县| 桑日县| 新邵县| 建平县| 杂多县| 宜兰市| 简阳市| 韶关市| 磴口县| 沐川县| 辽宁省| 厦门市| 肃宁县| 双牌县| 河西区| 增城市| 昆明市| 清水河县| 晋江市| 清水县| 林甸县|