冒泡事件

舉一個小例子,說明下對冒泡的理解javascript

準備工做與目的

首先,先寫html,就是一個按鈕+一個浮層,再加上點csscss

<body>
    <div id="wrap">
        <button id="clickme">Click Me</button>
        <div id="fuceng">
            gone with the wind
        </div>
    </div>
</body>

冒泡效果

而後,寫點js實現功能:點擊ClickMe按鈕彈出gone with the wind浮層,點擊別的地方隱藏浮層html

<script>
    $("#clickme").on("click",function(){
        console.log("clickme-clicked");
        $("#fuceng").show();

    })

    $(document).on("click",function(){
        console.log("document-clicked");
        $("#fuceng").hide();
    })
</script>

不難理解,點擊$("#clickme")$("#fuceng") show()出來,點擊文檔$(document)$("#fuceng") hide()java

問題的產生

在單擊$("#clickme")的時候並無顯示$("#fuceng"),爲何???見下圖
點擊按鈕不顯示浮層ide

問題解釋:遇到事件時,先按照黑色箭頭方向從祖先問到本身:捕捉事件,而後再按照紅色箭頭從本身問到祖先:冒泡事件。問的內容是:某某元素被xxx(事件名)了,你是否有函數要操做?函數

本例中,沒有捕捉階段,直接到冒泡階段。$("#clickme")被點擊後,操做了本身的函數:$("#fuceng").show();。那爲何$("#fuceng")不顯示呢???由於冒泡還沒結束,問過$("#clickme")後又問到了它的祖先$(document):你的一個子孫被點擊了,你有函數要操做嗎?有!!!而後操做了它的函數$("#fuceng").hide();,因此又被隱藏了。。。優化

爲了顯示過程,在兩個函數裏分別加上console.log,結果見下圖。
說明,先執行了$("#clickme")的函數,後執行了$(document)的函數。
冒泡顯示和隱藏spa

問題的解決

簡單再描述一遍,就是咱們同時在按鈕和頁面上綁定了onclick事件,結果就是觸發按鈕的onclick同時也觸發了頁面的onclick,由於按鈕在頁面裏面。code

其中一個解決方法就是,當觸發按鈕的onclick時,阻止冒泡事件再往上通知,示意圖以下。
阻止冒泡事件示意圖htm

代碼以下:

<script>
    $("#clickme").on("click",function(){
        console.log("clickme-clicked");
        $("#fuceng").show();
    })

    //新添加的代碼
    $("#wrap").on("click",function(e){
        e.stopPropagation();
    })

    $(document).on("click",function(){
        console.log("document-clicked");
        $("#fuceng").hide();
    })
</script>

在按鈕的父元素$("#wrap")上添加onclick事件,來阻止按鈕的onclick再向上通知。在$("#wrap")上阻止冒泡事件,使得不管在點擊按鈕仍是顯現出來的浮層都不會使浮層消失。

優化

假使頁面中有不少個浮層,像上面這樣每個浮層都監聽一次$(document)會大大的佔用內存,因此思路是使用one()方法,只在點擊按鈕的時候監聽一次$(document),代碼以下:

<script>
    $("#clickme").on("click",function(e){
        $("#fuceng").show();
        //新增代碼
        $(document).one("click",function(){
            $("#fuceng").hide();
        })
    })

    $("#wrap").on("click",function(e){
        e.stopPropagation();
    })
</script>

優化探究

上述優化代碼可否簡單成下面這樣呢?

<script>
    $("#clickme").on("click",function(e){
        $("#fuceng").show();
        //新增代碼
        $(document).one("click",function(){
            $("#fuceng").hide();
        })
    })
</script>

你看,我在點擊按鈕的時候只監聽一次$("document"),又沒有再點擊頁面了,應該沒問題吧?有問題!!!以下圖。
事件執行過程

點擊按鈕(藍色箭頭),調用裏面的函數,執行①、執行②。注意,這裏執行②就是再給頁面添加了一個點擊事件,且,在執行按鈕的點擊事件時,冒泡事件的追問是中止的。等調用完了,再接着問按鈕的父輩、祖輩們按鈕被點擊了,你有沒有函數須要調用啊?又問到了頁面,這時候頁面是有函數的,就是以前執行的②。

其實,除了使用阻止冒泡的方式阻止事件的傳播,還可使用setTimeout方法,使須要綁定給頁面的函數在冒泡詢問完成後再綁定。

<script>
    $("#clickme").on("click",function(e){
        $("#fuceng").show();
        setTimeout(function(){
            $(document).one("click",function(){
                $("#fuceng").hide();
            })
        },0)
    })
</script>

使用setTimeout展示冒泡過程

html:

<body>
    <div id="red">
        <div id="orange">
            <div id="yellow">
                <div id="green">
                    <div id="blue">
                        <div id="indigo">
                            <div id="purple"></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>

css:

#red.active{
    background: red;
}
#orange.active{
    background: orange;
}
#yellow.active{
    background: yellow;
}
#green.active{
    background: green;
}
#blue.active{
    background: blue;
}
#indigo.active{
    background: indigo;
}
#purple.active{
    background: purple;
}
#purple{
    min-height: 100px;
}
div{
    margin:10px;
    border: 1px solid black;
}

js:

var n=0;
$("div").on("click",function(e){
    setTimeout(function(){
        $(e.currentTarget).addClass("active");
    },n*1000)
    n+=1;
})

效果:
setTimeout冒泡展現

解釋:
html和css很好理解。js的意思就是點擊$("div")的時候,添加active類,即展示了背景顏色。本例中,點擊最內層<div id="purple"></div>的時候,冒泡事件開始詢問。

  • purple,等候n*1000後添加active類,當即執行n+=1
  • indigo,等候n*1000後添加active類,當即執行n+=1
  • blue,等候n*1000後添加active類,當即執行n+=1
  • green,等候n*1000後添加active類,當即執行n+=1
  • yellow,等候n*1000後添加active類,當即執行n+=1
  • orange,等候n*1000後添加active類,當即執行n+=1
  • red,等候n*1000後添加active類,當即執行n+=1

咱們該明白的是,全部事情是一步一步作的,即詢問下一個div時,n都是已經加過1了,並且,選擇器是$("div"),因此,全部div都綁定了事件。

相關文章
相關標籤/搜索