• 移动端弹出层后禁止背景底层 body滚动(part2)


    JS控制

    • 区别对待

    看来只通过 css来完成这个效果是有些难度了,于是将主意打到了 js上,如下:

    box1.addEventListener('touchmove', function(e){
        e.preventDefault()
    })

    直接禁止弹出层的掉滚动事件,因为弹出层是满屏覆盖在 页面上的,而且这个事件也没有 点透,所以确实是达到了禁止背景 页面滚动的效果。

    but,背景元素的滚动是禁止掉了,但这种禁止几乎是把页面上所有元素的滚动事件都禁止掉了,如果在弹出层元素 box1中存在可以滚动的元素,那么同样也会被禁止滚动,这可不是我们想要的,所以必须要把弹出层内的元素排除在外才行。

    弹出层内可滚动区域包括可滚动的顶级元素,以及此元素下所有的子元素,所以只要判断当前正在滚动的区域是此区域内的元素,则允许滚动,所以这里需要判断当前 touch的元素是不是弹出层内可以滚动的元素,以及是不是其子元素,判断是否为其子元素只需要一个循环递归即可,例如以下代码:

    function getRecursiveEle(ele, parentClassName) {
      if (ele.className.indexOf(parentClassName) !== -1) {
        return ele
      } else {
        if (ele.nodeName.toLowerCase() === 'body') {
          return null
        }
        ele = ele.parentNode
        return getRecursiveEle(ele, parentClassName)
      }
    }

    调用此函数,传入 e.target以及弹出层可以滚动的元素类名即可,返 回 true,则表明是可以滚动的元素。

    but,虽然你直接禁止了弹出层可滚动元素其外的元素滚动,然而同时又允许弹出层内可滚动元素滚动,那么当将滚动元素滚动到头的时候,背景还是会滚动。

    所以,还需要加一个判断,当滚动元素滚动到头或者尾部的时候,再禁止所有元素滚动,这里的滚动到头包括两种情况,到头和到尾。

    // 滚动到头的情况,其中touchstartY 为开始滚动时接触点的 `pageY`
    if(modal.scrollTop <= 0) {
        e.targetTouches[0].pageY > touchstartY && e.preventDefault()
    }
    // 滚动到尾的情况,其中touchstartY 为开始滚动时接触点的 `pageY`,itemH为可滚动元素框内部的子元素总高度,+2是因为边界问题
    (itemH - modal.offsetHeight < modal.scrollTop + 2) && (e.targetTouches[0].pageY < touchstartY) && e.preventDefault()

    这样的话,问题大体上解决了,但还有点小问题,在有的浏览器上,当可滚动元素滚动到头的时候,背景依旧还是会稍微滚动一点距离,不太完美。

    • 另想他法

    依旧让覆盖整个屏幕的弹出层禁止滚动,弹出层内部可滚动元素的滚动通过 js来控制,例如使用 translate控制上下滚动距离。

    // touchstartY 为touchstart事件发生时的 e.targetTouches[0].pageY
    var translateEndY = 0, translateEndYTemp  = 0
    box1.addEventListener('touchmove', function(e) {
        // 禁止默认滚动
        e.preventDefault()
        translateEndYTemp = e.targetTouches[0].pageY-touchstartY + translateEndY
        // 通过改变 translate来滚动元素
        $('.item').style.transform = 'translate(0, '+translateEndYTemp+'px)'
    })
    
    // 缓存下每次滚动过的距离
    box1.addEventListener('touchend', function(e) {
      translateEndY = translateEndYTemp
    })

    嗯,这样就差不多了,不过因为滚动时通过 translate实现的,所以滚动元素是不受父元素约束的,也就是说滚动元素会滚过界,这个很好解决,在 touchend的时候,判断一下有没有过界,如果过界了反弹回来就行。

  • 相关阅读:
    Java基础教程:多线程杂谈——双重检查锁与Volatile
    LeetCode:打印零与奇偶数【1116】
    Java基础教程:多线程基础(6)——信号量(Semaphore)
    LeetCode:交替打印【1115】
    做一件事情的3个关键指标:兴趣、能力和回报
    做一件事情的3个关键指标:兴趣、能力和回报
    Retry模式
    Java技术——String类为什么是不可变的
    2017战略No.2:开始电子化记账
    2017战略No.2:开始电子化记账
  • 原文地址:https://www.cnblogs.com/limingziqiang/p/8572287.html
Copyright © 2020-2023  润新知