移動頁面點選穿透問題解決方案
阿新 • • 發佈:2019-01-01
核心程式碼:
<div class="content">
<div id="underLayer">
<a href="www.baidu.com">連結</a>
<input type="text" class="text1" >
<input type="select" class="select">
<input type="radio" class="select">
<input type="checkbox" class="select">
<button class="btn" id="openPopup">彈出</button>
</div>
<div id="popupLayer">
<div class="layer-title">彈出層</div>
<div class="layer-action">
<button class="btn" id="closePopup">關閉</button>
</div>
</div>
</div>
<script type="text/javascript">
var oPop =document.getElementById('popupLayer');
var oUn = document.getElementById('underLayer');
var oOpen = document.getElementById('openPopup');
oPop.addEventListener('touchend', function(e){
this.style.display='none';
});
oUn.addEventListener('click',
function(){
alert('1');
} );
</script>
點選彈出層,touch事件首先被觸發,彈出層和遮罩就被隱藏了。touchend後繼續等待300ms發現沒有其他行為了,則繼續觸發click,由於這時彈出層已經消失,所以當前click事件的target就在底層元素上,於是就alert內容。整個事件觸發過程為 touchend -> click。
而由於click事件的滯後性(300ms),在這300ms內上層元素隱藏或消失了,下層同樣位置的DOM元素觸發了click事件(如果是input框則會觸發focus事件,如果是<a>連結則會進行頁面跳轉,或是 select / radio / checkbox都會被觸發),看起來就像點選的target“穿透”到下層去了。這就是點透現象
2.解決方法:
a、阻止預設事件 e.preventDefault() 給touchend事件加上 e.preventDefault()
oPop.addEventListener('touchend', function(e){
this.style.display='none';
e.preventDefault();
});
b、利用css3屬性 pointer-events
取值auto|none
當取值為auto 時,效果和沒有定義 pointer-events 屬性相同,滑鼠不會穿透當前層。
當取值為none 時,元素不再是滑鼠事件的目標,滑鼠不再監聽當前層而去監聽下面的層中的元素。但是如果它的子元素設定了pointer-events為其它值,比如auto,滑鼠還是會監聽這個子元素的。
詳細程式碼:
oPop.addEventListener('touchend', function(e){
this.style.display='none';
oUn.style.pointerEvents='none';
setTimeout(function(){
oUn.style.pointerEvents='auto';
}, 400);
});
c. 遮擋
由於 click 事件的滯後性,在這段時間內原來點選的元素消失了,於是便“穿透”了。因此我們順著這個思路就想到,可以給元素的消失做一個fade效果,類似jQuery裡的fadeOut,並設定動畫duration大於300ms,這樣當延遲的 click 觸發時,就不會“穿透”到下方的元素了。
同樣的道理,不用延時動畫,我們還可以在觸控位置放一個透明的元素,這樣當上層元素消失而延遲的click來到時,它點選到的是那個透明的元素,也不會“穿透”到底下。在一定的timeout後再將生成的透明元素隱藏。程式碼如下:
oPop.addEventListener('touchend', function(e){
oBg.style.display ='block';
this.style.display='none';
// 解決方法三
setTimeout(function(){
oBg.style.display='none'
}, 400);
});