移動端開發時經常會碰到有全屏遮罩層的彈窗滾動穿透問題,網上大部分的解決方案是彈窗出現時給body絕對定位或者高度設定為100%,並隱藏超出部分。
但是這些解決方法,都存在這樣的問題:當頁面有滾動時,彈出彈窗,頁面會滾動至頂部。特別是當頁面有其他根據document文件滾動距離而絕對定位元素時,會導致頁面元素混亂。
我經過查詢相關文件和實踐,發現可通過監聽touchmove和touchstart事件,來達到背景不可滾動而彈出窗可滾動的目的。可看此demo,建議在移動裝置上檢視。
下面詳細講解一下實現方法:
阻止彈窗的touchmove預設事件
當阻止了整個彈窗的touchmove預設事件後,背景將再也不會滾動。
var node = document.querySelector('.forbid-scroll-wrap');
node.addEventListener('touchmove', function (e) {
e.preventDefault();
}, false);
複製程式碼
但是這樣會導致彈窗內部也無法滾動。所以需要判斷觸發touchmove事件的元素是否為可滾動區域,程式碼優化如下:
var node1 = document.querySelector('.can-scroll-wrap'),
node2 = document.querySelector('.forbid-scroll-wrap');
node2.addEventListener('touchmove', function (e) {
var target = e.target;
if ($(target).parents(canScrollWrap).length === 0 && $(target) != node1) {
e.preventDefault();
}
}, false);
複製程式碼
允許彈窗內部滾動
以上只是解決了一個問題:滑動彈窗其他地方背景頁面確實未跟隨滾動,但是沒去彈窗可滾動區域到底部或頂部後,再滑動,背景頁面仍可跟隨滾動。
所以仍需要對可滾動區域的滑動事件做監聽:若向上滑動時,已到底部,或向下滑動時已到頂部,則阻止滑動事件。程式碼如下:
node1.scrollTop = 0;
var offsetHeight = node1.offsetHeight,
scrollHeight = node1.scrollHeight;
node2.addEventListener('touchmove', function (e) {
var target = e.target;
if ($(target).parents(canScrollWrap).length === 0 && $(target) != node1) {
e.preventDefault();
}
}, false);
node1.addEventListener('touchmove', function (e) {
var changedTouches = e.changedTouches, canMove = false;
var scrollTop = this.scrollTop;
if (changedTouches.length > 0) {
var touch = changedTouches[0] || {};
var moveY = touch.clientY;
if (moveY > startY && scrollTop <= 0) {
canMove = false;
} else if (moveY < startY && scrollTop + offsetHeight >= scrollHeight) {
canMove = false;
}else{
canMove = true;
}
if (!canMove) {
e.preventDefault();
}
}
}, false);
node1.addEventListener('touchstart', function (e) {
var targetTouches = e.targetTouches || [];
if (targetTouches.length > 0) {
var touch = targetTouches[0] || {};
startY = touch.clientY;
}
}, false)
複製程式碼
解除禁止
彈窗關閉後,可解除所有禁止
node1.addEventListener('touchstart',null,false);
node1.addEventListener('touchmove',null,false);
node2.addEventListener('touchmove',null,false);
複製程式碼