上一次進修了DOM 的事宜,明白了冒泡事宜和捕捉事宜,觸發的機制,本日進修一下詳細的運用場景,或者說在哪一個處所輕易踩坑。
做一個小demo,點擊按鈕湧現浮層,點擊別的處所封閉浮層,寫一個簡樸css
<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
,就能夠看到了。
clickMe.addEventListener('click',function(){
popover.style.display = 'block';
});
那該怎樣處理呢?最簡樸的要領是,除了要實行popover.style.display = 'block'
,還要阻撓事宜流傳
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)
和下面的代碼完整等價
$(wrapper).on('click',function(e){
e.preventDefault(); //阻撓默許事宜
e.stopPropagation(); //阻撓流傳
})
然則假如頁面中有checkbox
,你在它的父元素任何一層,包含checkbox
本身,增加了構造默許事宜那末這個checkbox
就沒辦法被check
。
這裡有個題目,假如沒有阻撓事宜流傳,向下面如許,會發作什麼事變呢?
$(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
上面,守候用戶下次點擊在實行。
<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>
總結:
- 同時監聽
button
和document
,點啥都沒迴響反映,由於兩個函數都實行了,用阻撓事宜流傳處理了,比較糟蹋內存 - 好肯定的要領是用jQuery 做,點擊
button
后在監聽document
,封閉了就不再監聽,不阻撓事宜流傳,點啥也沒迴響反映,兩種處理要領:一種是阻撓事宜流傳,另一種是增加一個setTimeout()
函數。