阻止事件傳播

上一次學習了DOM 的事件,理解了冒泡事件和捕獲事件,觸發的機制,今天學習一下具體的應用場景,或者說在哪一個地方容易踩坑。css

作一個小demo,點擊按鈕出現浮層,點擊其它地方關閉浮層,寫一個簡單csssegmentfault

<style>
.wrapper{
    position:relative;
    display:inline-block;
}
.popover{
    position:absolute;
    border:1px solid red;
    left:100%;
    top:0;
    padding:10px;
    margin-left:10px;
    background:white;
    display: none;  /*默認隱藏*/
}
.popover::before{
    position:absolute;
    content:'';
    top:5px;
    right:100%;
    border:10px solid transparent;
    border-right-color:red;
}
.popover::after{
    position:absolute;
    content:'';
    top:5px;
    right:100%;
    border:10px solid transparent;
    border-right-color:white;
    margin-right:-1px;
}

</style>
<div id="wrapper" class='wrapper'>
    <button id="clickMe">點我</button>
    <div id="popover" class="popover">
        <input type="checkbox">浮層
    </div>
</div>
<script>
    clickMe.addEventListener('click',function(){
        popover.style.display = 'block';
    });
</script>

那如今我要點擊頁面空白地方關閉呢?該用什麼方法,很容易想到監聽文檔,以下代碼瀏覽器

document.addEventListener('click',function(){
    popover.stely.display = 'none';
});

可是實際上這樣寫了以後,按鈕都失效了,怎麼點都沒有反應。這是爲何呢?
理解上一篇講的捕獲和冒泡事件後就很好理解這點了,能夠DOM事件之捕獲、冒泡
咱們沒有指定監聽是在捕獲仍是冒泡階段,瀏覽器默認是冒泡階段,當咱們點擊按鈕時,捕獲階段沒有發生何時,可是冒泡階段就不同了,首先button上函數先觸發,而後document上函數也觸發了,致使準備出現的浮層又被隱藏了。
那你可能要問,button上的事件執行了沒?其實這兩個事件都執行了,只是時間過短,瀏覽器默認一塊兒執行了,能夠在裏面加一個debugger,就能夠看到了。app

clickMe.addEventListener('click',function(){
    popover.style.display = 'block';
});

那該怎麼解決呢?最簡單的方法是,除了要執行popover.style.display = 'block',還要阻止事件傳播ide

clickMe.addEventlistener('click',function(){
    popover.style.display = 'block';
});

popover.addEventListener('click',function(e){
    e.stopPropagation();
});

這裏爲何添加在按鈕的父元素上面呢?若是不添加在父元素上面,點擊浮層的時候,浮層也會被關閉。函數

若是頁面上有不少監聽器的話,這個方法是比較浪費內存的,比較省內存的方法用JQuery 作學習

$(clickMe).on('click',function(){
    $(popover).show();
    $(document).one('click',function(){
        $(popover).hide();
    });
});
$(wrapper).on('click',function(e){
    e.stopPropagation();    
})

一開始不監聽,只在popover`show`的時候監聽一次,立刻關掉,這叫作清理戰場。
$(wrapper).on('click',false) 和下面的代碼徹底等價flex

$(wrapper).on('click',function(e){
    e.preventDefault();     //阻止默認事件
    e.stopPropagation();    //阻止傳播
})

可是若是頁面中有checkbox,你在它的父元素任何一層,包括checkbox本身,添加了組織默認事件那麼這個checkbox就沒辦法被checkspa

這裏有個問題,若是沒有阻止事件傳播,向下面這樣,會發生什麼事情呢?debug

$(clickMe).on('click',function(){
    $(popover).show();
    $(document).one('click',funtion(){
        $(popover).hide();
    });
});

固然了,和以前同樣,什麼事情也不會發生,那當我點擊按鈕以後裏面都發生了那些事情呢?
當我點擊了按鈕以後,它會作兩件事情,首先把popover`show出來,而後把hide函數添加到document上面,當事件傳播到document`,就會又把它給隱藏了。

能夠給它添加一個setTimeout()函數來解決這個問題

$(clickMe).on('click',function(){
    $(popover).show();
    setTimeout(function(){
        $(document).one('click',function(){
            $(popover).hide();
        })
    },0)
});

setTimeout(fn,0)這個0不是立刻執行,而是儘快執行,具體是在冒泡結束在執行這裏的函數,也就是說,當冒泡結束後,在把監聽事件添加到document上面,等待用戶下次點擊在執行。

用 jQuery 作事件冒泡

<style>
.red.active{
  background:red;
}
.blue.active{
  background:blue;
}
.green.active{
  background:green;
}
.yellow.active{
  background:yellow;
}
.orange.active{
  background:orange;
}
.purple.active{
  background:purple;
}
div{
  border:1px solid black;
  display:flex;
  flex:1;
  padding:20px;
  transition:1s;
  border-radius:100%;
}
*{
  padding:0;
  margin:0;
  box-sizing:border-box;
}
.red{
  height:300px;
  width:300px;
}
</style>
<div class="red">
  <div class="blue">
    <div class="green">
      <div class="yellow">
        <div class="orange">
          <div class="purple"></div>
        </div>
      </div>
    </div>
  </div>
</div>
<script>
var n = 1
$('div').on('click',function(e){
  setTimeout(function(){
    $(e.currentTarget).addClass('active')  
  },n*500)
  n+=1
})
</script>

總結:

  1. 同時監聽buttondocument,點啥都沒反應,由於兩個函數都執行了,用阻止事件傳播解決了,比較浪費內存
  2. 好必定的方法是用jQuery 作,點擊button後在監聽document,關閉了就再也不監聽,不阻止事件傳播,點啥也沒反應,兩種解決方法:一種是阻止事件傳播,另外一種是添加一個setTimeout()函數。
相關文章
相關標籤/搜索