移動端滾動穿透解決方案

移動端開發時常常會碰到有全屏遮罩層的彈窗滾動穿透問題,網上大部分的解決方案是彈窗出現時給body絕對定位或者高度設置爲100%,並隱藏超出部分。html

可是這些解決方法,都存在這樣的問題:當頁面有滾動時,彈出彈窗,頁面會滾動至頂部。特別是當頁面有其餘根據document文檔滾動距離而絕對定位元素時,會致使頁面元素混亂。node

我通過查詢相關文檔和實踐,發現可經過監聽touchmove和touchstart事件,來達到背景不可滾動而彈出窗可滾動的目的。可看此demo,建議在移動設備上查看。git

下面詳細講解一下實現方法:github

阻止彈窗的touchmove默認事件

當阻止了整個彈窗的touchmove默認事件後,背景將不再會滾動。bash

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);
複製代碼

容許彈窗內部滾動

以上只是解決了一個問題:滑動彈窗其餘地方背景頁面確實未跟隨滾動,可是沒去彈窗可滾動區域到底部或頂部後,再滑動,背景頁面仍可跟隨滾動。this

因此仍須要對可滾動區域的滑動事件作監聽:若向上滑動時,已到底部,或向下滑動時已到頂部,則阻止滑動事件。代碼以下:spa

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)

複製代碼

解除禁止

彈窗關閉後,可解除全部禁止code

node1.addEventListener('touchstart',null,false);
node1.addEventListener('touchmove',null,false);
node2.addEventListener('touchmove',null,false);
複製代碼

點此查看源碼htm

相關文章
相關標籤/搜索