React项目实战(三)尝试实现一个拉动刷新组件

栏目: CSS · 发布时间: 6年前

内容简介:分析:我们需要实现两个方向(向下拉动,向上滑动)上的拉动刷新,考虑完成 PullDownRefresh 和 PullUpRefresh 两个组件的编写。思考其中细节:① 自适应滚动的内容是基于页面还是基于内部容器;② 组件是否可以组合使用;

分析:我们需要实现两个方向(向下拉动,向上滑动)上的拉动刷新,考虑完成 PullDownRefresh 和 PullUpRefresh 两个组件的编写。思考其中细节:

① 自适应滚动的内容是基于页面还是基于内部容器;

② 组件是否可以组合使用;

③ 状态提示loading如何设计;

④ loading开始与结束的时机,定时器规定时间?数据加载完结束?

目前实现

① 暂时未考虑页面和内部容器同时滑动的情况;

② 通过 props.children 传入需要拉动刷新的内容,两个组件可组合使用;

③ 通过一个 refreshing 状态变量来决定当前是否处于刷新状态;

④ 通过在 componentWillReceiveProps 生命周期钩子中接收新状态/数据来控制 loading 的结束,即 refreshing=false

依旧是模仿掘金主页的实现

React项目实战(三)尝试实现一个拉动刷新组件

预备知识

弄清楚元素的几个属性值(翻一下MDN吧)

  • clientHeight:这个属性是只读属性,对于没有定义CSS或者内联布局盒子的元素为0,否则,它是 元素 内部的高度(单位像素),包含内边距,但不包括水平滚动条、边框和外边距
React项目实战(三)尝试实现一个拉动刷新组件
  • offsetHeight 是一个DOM属性。它有时被称为一个 元素 的物理/图形的尺寸,或是一个元素的边界框(border-box)的高度。

    React项目实战(三)尝试实现一个拉动刷新组件
  • scrollTop 属性可以获取或设置一个 元素 的内容垂直滚动的像素数。部到视口可见内容(的顶部)的距离的度量。当一个元素的内容没有产生垂直方向的滚动条,那么它的 scrollTop 值为0

React项目实战(三)尝试实现一个拉动刷新组件
  • scrollHeight:这个只读属性是一个 元素 内容高度的度量,包括由于溢出导致的视图中不可见内容。(属性将会对值四舍五入取整)。包括元素的padding,但不包括元素的border和margin。scrollHeight也包括 ::before::after 这样的伪元素。
    React项目实战(三)尝试实现一个拉动刷新组件
    判断是否滚动到底部:
    element.scrollHeight - element.scrollTop === element.clientHeight 
    
  • getBoundingClientRect() 方法返回 元素 的大小及其相对于视口的位置。
React项目实战(三)尝试实现一个拉动刷新组件
  • Window​.scrollY:返回文档在垂直方向已滚动的像素值。跨浏览器兼容:
    var supportPageOffset = window.pageXOffset !== undefined;
    var isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");
    var y = supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop;
    复制代码
  • Touch​.pageY:触点相对于HTML文档上边沿的的Y坐标. 和 clientY 属性不同, 这个值是相对于整个html文档的坐标, 和用户滚动位置无关. 因此当存在垂直滚动的偏移时, 这个值包含了垂直滚动的偏移

下拉刷新组件

首先要明确的是下拉刷新组件的触发条件:① 内容垂直滚动的距离应该为0;② 触屏拉动的距离应该大于某个给定的阈值;③ 明确究竟是哪个容器设置了内容自动滚动。下面以我写的具体例子作为参考(没有考虑复杂情况)

  • 在container页面使用 PullDownRefresh 套了需要下拉刷新的内容,这里 scroll_content 设置了 overflow-y:auto
<div className="main scroll_content">
  <PullDownRefresh
    onRefresh={this._onRefreshDown}
    refreshing={this.state.refreshing}>
      {entryList.map((element, index) => {
        return <EntryItem item={element} key={index} />
      })}
  </PullDownRefresh>
复制代码
  • 在PullDownRefresh组件中
<>
  {this.state.refreshing ? <RefreshLoading orient="up" /> : null}
  <div
    ref={el => (this.scrollContent = el)}
    onTouchStart={this.handleTouchStart}
    onTouchMove={this.handleTouchMove}
    onTouchEnd={this.handleTouchEnd}
  >
    {this.props.children}
  </div>
</>
复制代码
  • 在 handleTouchStart 中我们记录初始触屏点位置
handleTouchStart = e => {
  this.setState({
    startPos: e.touches[0].pageY
  })
}
复制代码
  • 在 handleTouchMove 中,如果两个触屏点距离大于minHeight,且当前不处于正在刷新状态,且内容滚动高度为0,那么可以开始加载( refreshing: true
handleTouchMove = e => {
  if (
    this.state.refreshing === false &&
    this.state.parentNode.scrollTop === 0
  ) {
    let _pullHeight = e.touches[0].pageY - this.state.startPos
    if (_pullHeight > this.state.minHeight) {
      this.setState({
        refreshing: true
      })
    }
  }
}
复制代码
  • 在 handleTouchEnd 中,我们进行数据更新请求。因为我们观察刷新操作是释放之后才开始进行的,而且在move中进行的话可能多次触发
handleTouchEnd = e => {
  if (this.state.refreshing) {
    this.props.onRefresh()
  }
}
复制代码
  • 如果我们直接在页面进行请求,可以在promise的finally之后,设置更新结束( refreshing: false );如果我们是使用外部传入的数据,需要在 componentWillReceiveProps 中设置更新结束( refreshing: false
componentWillReceiveProps(nextProps) {
  if (nextProps.refreshing !== this.state.refreshing) {
    this.setState({
      refreshing: nextProps.refreshing
    })
  }
}
复制代码
  • 获取滚动容器的方法,可以在componentDidMount生命周期中获取
var scrollContent = ReactDOM.findDOMNode(this.scrollContent).parentNode
复制代码
  • 基于页面滚动
var isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");
var scrollContent = isCSS1Compat ? document.documentElement : document.body;
复制代码

上滑加载组件

原理类似,不过多赘述,判断到达底部的条件是:

parentNode.scrollHeight - parentNode.scrollTop - parentNode.clientHeight === 0
复制代码

浏览器兼容

我们既想要滚动的功能,又不希望内部容器显示滚动条,考虑为内部容器添加类 scroll_content 实现

::-webkit-scrollbar {
    /*隐藏滚轮*/
    display: none;
}
.scroll_content {
    -ms-scroll-chaining: chained;
    -ms-overflow-style: none;
    -ms-content-zooming: zoom;
    -ms-scroll-rails: none;
    -ms-content-zoom-limit-min: 100%;
    -ms-content-zoom-limit-max: 500%;
    -ms-scroll-snap-type: proximity;
    -ms-scroll-snap-points-x: snapList(100%, 200%, 300%, 400%, 500%);
    -ms-overflow-style: none;
    overflow: auto;
    -ms-overflow-style: none;
    overflow: -moz-scrollbars-none;
}
复制代码

--

总结:

① 一些功能仍待完善,有必要两个组件可组合使用吗?内部容器滚动时禁止外部页面滚动;

② componentWillReceiveProps 是经常使用的一个生命周期钩子,包括在参数路由改变时更新数据;

项目地址


以上所述就是小编给大家介绍的《React项目实战(三)尝试实现一个拉动刷新组件》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Code

Code

Charles Petzold / Microsoft Press / 2000-10-21 / USD 29.99

Paperback Edition What do flashlights, the British invasion, black cats, and seesaws have to do with computers? In CODE, they show us the ingenious ways we manipulate language and invent new means of ......一起来看看 《Code》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具