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

基于事件冒泡、事件捕獲和事件委托詳解

 更新時(shí)間:2021年07月08日 11:41:28   作者:晏子楚  
這篇文章主要介紹了事件冒泡、事件捕獲和事件委托,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

事件冒泡、事件捕獲和事件委托

在javascript里,事件委托是很重要的一個(gè)東西,事件委托依靠的就是事件冒泡和捕獲的機(jī)制,我先來解釋一下事件冒泡和事件捕獲:

事件冒泡會(huì)從當(dāng)前觸發(fā)的事件目標(biāo)一級(jí)一級(jí)往上傳遞,依次觸發(fā),直到document為止。

事件捕獲會(huì)從document開始觸發(fā),一級(jí)一級(jí)往下傳遞,依次觸發(fā),直到真正事件目標(biāo)為止。

這么說是不是很抽象,其實(shí)就像我敲擊了一下鍵盤,我在敲擊鍵盤的同時(shí),我是不是也敲擊了這臺(tái)電腦,我寫個(gè)例子大家就明白了:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <style type="text/css">
        #box1 { width: 300px; height: 300px; background: blueviolet; }
        #box2 { width: 200px; height: 200px; background: aquamarine; }
        #box3 { width: 100px; height: 100px; background: tomato; }
        div { overflow: hidden; margin: 50px auto; }
    </style>
    <body>
        <div id="box1">
            <div id="box2">
                <div id="box3"></div>
            </div>
        </div>
        <script>
            function sayBox3() {
                console.log('你點(diǎn)了最里面的box');
            }
            function sayBox2() {
                console.log('你點(diǎn)了最中間的box');
            }
            function sayBox1() {
                console.log('你點(diǎn)了最外面的box');
            }
            // 事件監(jiān)聽,第三個(gè)參數(shù)是布爾值,默認(rèn)false,false是事件冒泡,true是事件捕獲
            document.getElementById('box3').addEventListener('click', sayBox3, false);
            document.getElementById('box2').addEventListener('click', sayBox2, false);
            document.getElementById('box1').addEventListener('click', sayBox1, false);
        </script>
    </body>
</html>

我們畫了三個(gè)box,結(jié)構(gòu)是父子關(guān)系,分別綁定了打印事件,現(xiàn)在我們來點(diǎn)擊最中間的紅色box:

我們發(fā)現(xiàn),我們僅僅是點(diǎn)擊了紅色的box,但是綠色和紫色的box也被觸發(fā)了打印事件,觸犯順序是 紅色>綠色>紫色,這種現(xiàn)象就是事件冒泡了。

我們?cè)僭囋囀录东@,把上面代碼里監(jiān)聽事件的第三個(gè)參數(shù)改為true,然后點(diǎn)擊紅色的box:

我們還是只點(diǎn)擊最中間的紅色box,和上一次一樣,也是三個(gè)box都觸發(fā)了事件,但是順序反過來了,紫色>綠色>紅色,這種現(xiàn)象稱為事件捕獲。

通過上面的例子,應(yīng)該很容易就理解了事件冒泡和事件捕獲,我們平時(shí)都是默認(rèn)冒泡的,冒泡是一直冒到document根文檔為止。

現(xiàn)在來談?wù)勈录?,事件委托又稱之為事件代理,我們通過一個(gè)通俗的例子來解釋:

有三個(gè)同事預(yù)計(jì)會(huì)在周一收到快遞,為了簽收快遞,有兩種辦法:1.三個(gè)人在公司門口等快遞;2.委托給前臺(tái)MM代為簽收?,F(xiàn)實(shí)當(dāng)中,我們大都采用委托的方案(公司也不會(huì)容忍那么多員工站在門口就為了等快遞)。前臺(tái)MM收到快遞后,她會(huì)判斷收件人是誰,然后按照收件人的要求簽收,甚至代為付款。這種方案還有一個(gè)優(yōu)勢(shì),那就是即使公司里來了新員工(不管多少),前臺(tái)MM也會(huì)在收到寄給新員工的快遞后核實(shí)并代為簽收(可以給暫時(shí)不存在的節(jié)點(diǎn)也綁定上事件)。

我們?cè)倥e另一個(gè)例子:

現(xiàn)在有一個(gè)ul,ul里又有100個(gè)li,我想給這100個(gè)li都綁定一個(gè)點(diǎn)擊事件,我們一般可以通過for循環(huán)來綁定,但是要是有1000個(gè)li呢? 為了提高效率和速度,所以我們這時(shí)可以采用事件委托,只給ul綁定一個(gè)事件,根據(jù)事件冒泡的規(guī)則,只要你點(diǎn)了ul里的每一個(gè)li,都會(huì)觸發(fā)ul的綁定事件,我們?cè)趗l綁定事件的函數(shù)里通過一些判斷,就可以給這100li都觸發(fā)點(diǎn)擊事件了。

具體怎么實(shí)現(xiàn),看代碼:

// 這里不講IE,結(jié)尾再說
function clickLi() {
    alert('你點(diǎn)擊了li');
}
document.getElementById('isUl').addEventListener('click', function(event) {
    // 每一個(gè)函數(shù)內(nèi)都有一個(gè)event事件對(duì)象,它有一個(gè)target屬性,指向事件源
    var src = event.target;
    // 我們判斷如果target事件源的節(jié)點(diǎn)名字是li,那就執(zhí)行這個(gè)函數(shù)
    // target里面的屬性是非常多的,id名、class名、節(jié)點(diǎn)名等等都可以取到
    if(src.nodeName.toLowerCase() == 'li') {
       clickLi() ;
    }
});

這樣我們就通過給ul綁定一個(gè)點(diǎn)擊事件,讓所有的li都觸發(fā)了函數(shù)。

那如果想給不同的li綁定不同的函數(shù)怎么辦?

假設(shè)有3個(gè)li,我們先寫3個(gè)不同的函數(shù),再給3個(gè)li設(shè)置不同的id名,通過判斷id名是不是就能給不同的li綁定不同的函數(shù)啦:

<body>
    <ul id="isUl">
        <li id="li01">1</li>
        <li id="li02">2</li>
        <li id="li03">3</li>
    </ul>
    <script>
        function clickLi01() {
            alert('你點(diǎn)擊了第1個(gè)li');
        }
        function clickLi02() {
            alert('你點(diǎn)擊了第2個(gè)li');
        }
        function clickLi03() {
            alert('你點(diǎn)擊了第3個(gè)li');
        }
        document.getElementById('isUl').addEventListener('click', function(event) {
            var srcID = event.target.id;
            if(srcID == 'li01'){
                clickLi01();
            }else if(srcID == 'li02') {
                clickLi02();
            }else if(srcID == 'li03') {
                clickLi03();
            }
        });
    </script>
</body>

這就是所謂的事件委托,通過監(jiān)聽一個(gè)父元素,來給不同的子元素綁定事件,減少監(jiān)聽次數(shù),從而提升速度。

那么,能不能阻止元素的事件冒泡呢,答案是可以的。

一開始那個(gè)例子,假如我們真的只想點(diǎn)擊最里面的那個(gè)紅色box,不想另外兩個(gè)box的事件被觸發(fā),我們可以在給紅色box綁定事件的函數(shù)里這么寫:

function sayBox3(event) {
    // 阻止冒泡
    event.stopPropagation();
    console.log('你點(diǎn)了最里面的box');
}
document.getElementById('box3').addEventListener('click', sayBox3, false);

這樣我們?cè)冱c(diǎn)擊紅色的box,那就只會(huì)觸發(fā)它本身的事件啦。

那阻止冒泡有沒有實(shí)際用途呢?答案是有的,我們看這個(gè)例子:

這是一個(gè)模態(tài)框,現(xiàn)在的需求是當(dāng)我們點(diǎn)擊紅色的按鈕需要跳轉(zhuǎn)頁面,然后點(diǎn)擊白色的對(duì)話框不需要任何反應(yīng),點(diǎn)其它任何地方就關(guān)閉這個(gè)模態(tài)框。

這里就需要用到阻止冒泡了,紅色的按鈕是白色對(duì)話框的子元素,白色對(duì)話框又是這整個(gè)模態(tài)框的子元素,我們給模態(tài)框加上一個(gè)點(diǎn)擊事件關(guān)閉,然后給紅色的按鈕加上一個(gè)點(diǎn)擊事件跳轉(zhuǎn),這時(shí)就產(chǎn)生了一個(gè)問題,只要點(diǎn)擊白色的對(duì)話框,由于冒泡機(jī)制,這個(gè)模態(tài)框也會(huì)關(guān)閉,實(shí)際上我們并不想點(diǎn)擊白色的對(duì)話框有任何反應(yīng),這時(shí)我們就給這個(gè)白色的對(duì)話框綁定一個(gè)點(diǎn)擊事件,函數(shù)里寫上event.stopPropagation();,這樣就OK了。

關(guān)于IE

老版本的IE存在兼容問題,根本不支持addEventListener()的添加事件和removeEventListener()的刪除事件,它有自己的監(jiān)聽方法:

// 添加事件,事件流固定為冒泡
attachEvent(事件名,事件處理函數(shù))
// 刪除事件
detachEvent(事件名,事件處理函數(shù))

還有IE里的事件對(duì)象是window.event,事件源是srcElement,阻止冒泡寫法也不一樣:

function() {
    // IE里阻止冒泡
    window.event.cancelBubble = true;
    // IE里獲取事件源的id
    var srcID = window.event.srcElement.id;
}
function(event) {
    // 非IE里阻止冒泡
    event.stopPropagation();
    // 非IE里獲取事件源的id
    var srcID = event.target.id;
}

補(bǔ)充

關(guān)于js的瀏覽器兼容問題,一般用能力檢測(cè)來解決,if(){}else{}

我們平時(shí)工作一般都是用jquery,IE這些特殊情況早就幫我們做好兼容啦。

jquery在1.7的版本之后,最流行的事件監(jiān)聽方法是$(元素).on(事件名,執(zhí)行函數(shù)),它還有一種事件委托的寫法$(委托給哪個(gè)元素).on(事件名,被委托的元素,執(zhí)行函數(shù))

最后說一點(diǎn),如果元素被阻止冒泡了,千萬別去用事件委托的方式監(jiān)聽事件,因?yàn)槭录械脑硎抢檬录芭荩?dāng)冒泡被阻止,就無法監(jiān)聽了。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • javascript運(yùn)動(dòng)框架用法實(shí)例分析(實(shí)現(xiàn)放大與縮小效果)

    javascript運(yùn)動(dòng)框架用法實(shí)例分析(實(shí)現(xiàn)放大與縮小效果)

    這篇文章主要介紹了javascript運(yùn)動(dòng)框架用法,結(jié)合實(shí)例形式分析了javascript運(yùn)動(dòng)框架的實(shí)現(xiàn)與使用技巧,可實(shí)現(xiàn)div塊的放大與縮小功能,需要的朋友可以參考下
    2016-01-01
  • 利用圖片的 onerror 事件載入默認(rèn)圖片

    利用圖片的 onerror 事件載入默認(rèn)圖片

    當(dāng)圖片不存在時(shí)載入默認(rèn)圖片的代碼
    2009-12-12
  • javascript div 彈出可拖動(dòng)窗口

    javascript div 彈出可拖動(dòng)窗口

    創(chuàng)建彈出div窗口。
    2009-02-02
  • JS之延時(shí)器和定時(shí)器執(zhí)行示例詳解

    JS之延時(shí)器和定時(shí)器執(zhí)行示例詳解

    這篇文章主要為大家介紹了JS之延時(shí)器和定時(shí)器執(zhí)行示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • javascript 不讓鼠標(biāo)事件觸發(fā)

    javascript 不讓鼠標(biāo)事件觸發(fā)

    div上加了onclick事件,里面又有超鏈a,點(diǎn)超鏈的時(shí)候能不觸發(fā)div 的事件嗎?
    2007-12-12
  • Javascript中的call()方法介紹

    Javascript中的call()方法介紹

    這篇文章主要介紹了Javascript中的call()方法介紹,本文講解了Call() 語法、Call() 參數(shù)、Javascript中的call()方法、Call()方法的實(shí)例等內(nèi)容,需要的朋友可以參考下
    2015-03-03
  • electron制作仿制qq聊天界面的示例代碼

    electron制作仿制qq聊天界面的示例代碼

    這篇文章主要介紹了electron制作仿制qq聊天界面的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-11-11
  • js+HTML5 canvas 實(shí)現(xiàn)簡單的加載條(進(jìn)度條)功能示例

    js+HTML5 canvas 實(shí)現(xiàn)簡單的加載條(進(jìn)度條)功能示例

    這篇文章主要介紹了js+HTML5 canvas 實(shí)現(xiàn)簡單的加載條(進(jìn)度條)功能,涉及javascript使用時(shí)間函數(shù)與canvas繪圖結(jié)合實(shí)現(xiàn)進(jìn)度條的相關(guān)操作技巧,需要的朋友可以參考下
    2019-07-07
  • 最新評(píng)論

    六安市| 儋州市| 尉犁县| 香港| 滨州市| 兰溪市| 龙陵县| 台前县| 卓尼县| 应城市| 衡水市| 南充市| 遂宁市| 光泽县| 高雄市| 夏津县| 金堂县| 南宁市| 阜康市| 渝中区| 酉阳| 永登县| 抚远县| 北京市| 泽库县| 潮州市| 九龙坡区| 壤塘县| 射阳县| 牡丹江市| 阿坝县| 桐城市| 从江县| 都兰县| 水富县| 德惠市| 榆社县| 葵青区| 广德县| 景洪市| 克东县|