Ant-design-mobile: iphone手机上,rc-dialog相关组件,内容部分没有阻止冒泡,可以触发页面滚动

Created on 17 Oct 2017  ·  13Comments  ·  Source: ant-design/ant-design-mobile

Version

1.6.11

Environment

ios

Reproduction link

https://mobile.ant.design/kitchen-sink/components/modal?lang=zh-CN

Steps to reproduce

点击"modal对话框(ios)"按钮,在内容部分上下滑动,会触发整个页面的滚动

What is expected?

不滚动

What is actually happening?

滚动

Need Reproduce

Most helpful comment

最近整合了一个更加完善的fix的代码,送给有缘人~

function closest(el, selector) {
  const matchesSelector =
    el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector
  while (el) {
    if (matchesSelector.call(el, selector)) {
      return el
    }
    el = el.parentElement
  }
  return null
}

/**
 * 修复antd-mobile Modal组件touch事件穿透
 * 需要滚动的地方请加class: 'scroller'
 * 参考代码:
 * https://mobile.ant.design/components/modal-cn/
 * http://www.zhangxinxu.com/study/201612/mobile-scroll-prevent-window-scroll.html
 */

export default function fixModal() {
  let data = {
    scroller: null,
    posY: 0,
    scrollY: 0,
    maxscroll: 0
  }

  function isIosModalVisible() {
    return (
      /iPhone|iPod|iPad/i.test(navigator.userAgent) &&
      document.body.style.overflow === 'hidden' &&
      document.querySelectorAll('.am-modal').length > 0
    )
  }

  document.body.addEventListener(
    'touchstart',
    function(e) {
      if (!isIosModalVisible()) return

      const scroller = closest(e.target, '.scroller')
      if (!scroller) return

      data.scroller = scroller
      // 垂直位置标记
      data.posY = e.touches[0].pageY
      data.scrollY = scroller.scrollTop
      // 是否可以滚动
      data.maxscroll = scroller.scrollHeight - scroller.clientHeight
    },
    { passive: false }
  )

  document.body.addEventListener(
    'touchmove',
    function(e) {
      if (!isIosModalVisible()) return

      if (!data.scroller) {
        return e.preventDefault()
      }

      const scrollTop = data.scroller.scrollTop
      const distanceY = e.touches[0].pageY - data.posY

      // 上下边缘检测
      if (distanceY > 0 && scrollTop === 0) {
        // 往上滑,并且到头
        // 禁止滚动的默认行为
        return e.preventDefault()
      }

      // 下边缘检测
      if (distanceY < 0 && scrollTop + 1 >= data.maxscroll) {
        // 往下滑,并且到头
        // 禁止滚动的默认行为
        return e.preventDefault()
      }
    },
    { passive: false }
  )

  document.body.addEventListener(
    'touchend',
    function(e) {
      if (!isIosModalVisible()) return
      data.scroller = null
      data.maxscroll = 0
    },
    { passive: false }
  )
}


All 13 comments

It will be better to write your issue/comment in English, so more people can understand you.
And this means that more people can help you or benefit from your issue/comment.
See: https://github.com/ant-design/ant-design/issues/4897

@daqi https://github.com/ant-design/ant-design-mobile/blob/master/components/modal/Modal.tsx#L30

这个是做了处理的,不应当会有问题,我这边也没能重现

@silentcloud 我也看了源码,这部分只是处理了mask,没有处理内容部分

@daqi 不处理 content 是有原因的,当非 alert,prompt 这种,纯 modal 如果 content overflow:scroll 是没法滚动的

我这边处理一下内置的 alert,prompt,operation,对于modal 自身,开放出去 wrapProps(用户根据自己情况决定要不要全部处理)

@silentcloud 同意

最近整合了一个更加完善的fix的代码,送给有缘人~

function closest(el, selector) {
  const matchesSelector =
    el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector
  while (el) {
    if (matchesSelector.call(el, selector)) {
      return el
    }
    el = el.parentElement
  }
  return null
}

/**
 * 修复antd-mobile Modal组件touch事件穿透
 * 需要滚动的地方请加class: 'scroller'
 * 参考代码:
 * https://mobile.ant.design/components/modal-cn/
 * http://www.zhangxinxu.com/study/201612/mobile-scroll-prevent-window-scroll.html
 */

export default function fixModal() {
  let data = {
    scroller: null,
    posY: 0,
    scrollY: 0,
    maxscroll: 0
  }

  function isIosModalVisible() {
    return (
      /iPhone|iPod|iPad/i.test(navigator.userAgent) &&
      document.body.style.overflow === 'hidden' &&
      document.querySelectorAll('.am-modal').length > 0
    )
  }

  document.body.addEventListener(
    'touchstart',
    function(e) {
      if (!isIosModalVisible()) return

      const scroller = closest(e.target, '.scroller')
      if (!scroller) return

      data.scroller = scroller
      // 垂直位置标记
      data.posY = e.touches[0].pageY
      data.scrollY = scroller.scrollTop
      // 是否可以滚动
      data.maxscroll = scroller.scrollHeight - scroller.clientHeight
    },
    { passive: false }
  )

  document.body.addEventListener(
    'touchmove',
    function(e) {
      if (!isIosModalVisible()) return

      if (!data.scroller) {
        return e.preventDefault()
      }

      const scrollTop = data.scroller.scrollTop
      const distanceY = e.touches[0].pageY - data.posY

      // 上下边缘检测
      if (distanceY > 0 && scrollTop === 0) {
        // 往上滑,并且到头
        // 禁止滚动的默认行为
        return e.preventDefault()
      }

      // 下边缘检测
      if (distanceY < 0 && scrollTop + 1 >= data.maxscroll) {
        // 往下滑,并且到头
        // 禁止滚动的默认行为
        return e.preventDefault()
      }
    },
    { passive: false }
  )

  document.body.addEventListener(
    'touchend',
    function(e) {
      if (!isIosModalVisible()) return
      data.scroller = null
      data.maxscroll = 0
    },
    { passive: false }
  )
}


This doesn't work on android 5.0 WebView, when I touch the Modal, the bottom layer was scrolled

补充点资料,希望对大家有用
使用 wrapProps 是无法组织冒泡的,现在默认注册滚动事件passive为true,导致了preventDefault 失效。
In Chrome stable / Safari / feature that treats document level Wheel/Mousewheel event listeners as Passive
参考 https://github.com/facebook/react/issues/6436

补充点资料,希望对大家有用
使用 wrapProps 是无法组织冒泡的,现在默认注册滚动事件passive为true,导致了preventDefault 失效。
In Chrome stable / Safari / feature that treats document level Wheel/Mousewheel event listeners as Passive
参考 facebook/react#6436

@ycscholes 大哥,请教一下,antd mobile中modal怎么禁止背景背面的滚动,modal里面的内容可以滚动,确实使用wrapProps没有办法

目前比较简单的解决办法是:
打开的时候把body设成position: fixed,并记录scrollTop,
关闭的时候再还原回来

这个不只是 iphone 吧,我安卓也这样啊?!

可以试下在弹窗弹出时,给body添加

{
  touch-action: none;
  overscroll-behavior: none;
  -webkit-overflow-scrolling: auto;
  overflow: hidden;
}

不过只支持ios 13+

Was this page helpful?
0 / 5 - 0 ratings