React 初探(十四)

2019-02-18  本文已影响17人  bowen_wu

概述

接下来我们将要完成 Home 页面。Home 页面主要有两个点

  1. 使用 react-sticky
  2. ant-design-mobileModal 组件的背景滚动问题

Home 页面 UI

Home UI

Home 页面功能

  1. 点击头像去往个人中心页面
  2. 页面可以滚动,滚动的时候 searchBar 会 sticky 顶部
  3. 可以通过事件 title 进行搜索
  4. 点击右下方的 + 可以去往创建 TODO 页面

react-sticky

Home 页面主要使用了 ant-design-mobileListView 组件,其中借助 react-sticky 将搜索栏在滚动的过程中 sticky 在顶部。这里有官方例子和一些使用方法

ant-design-mobileModal 组件的背景滚动问题

这个主要是一个在 IOS 下的问题,当页面可以滚动时,有 Modal 显示的时候,此时滚动页面,Modal 后的页面会跟着滚动。ant-design-mobile 有在文档中说明解决方法,但是我在实践的过程中发现并不能解决。所以又搜索了一下,找到了一个可以解决的方法。

ant-design-mobile 解决方法

  1. 定义一个 closet 函数
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;
}
  1. Modal 中添加 wrapProps 属性
 wrapProps={{ onTouchStart: this.onWrapTouchStart }}
  1. 在组件上定义 onWarpTouchStart 函数
  onWrapTouchStart = (e) => {
    // fix touch to scroll background page on iOS
    if (!/iPhone|iPod|iPad/i.test(navigator.userAgent)) {
      return;
    }
    const pNode = closest(e.target, '.am-modal-content');
    if (!pNode) {
      e.preventDefault();
    }
  }

搜索到可以解决的方法

  1. 创建一个 fixModalTouchBGScroll.js 文件
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
        }
    )
}
  1. 在需要使用的组件中引入并在 componentWillMount 生命周期函数中调用
import FixModalTouchBGScroll from 'path/fixModalTouchBGScroll';

componentWillMount() {
    FixModalTouchBGScroll();
}
  1. 需要滚动的地方加class -> scroller
上一篇下一篇

猜你喜欢

热点阅读