内容简介:分析:我们需要实现两个方向(向下拉动,向上滑动)上的拉动刷新,考虑完成 PullDownRefresh 和 PullUpRefresh 两个组件的编写。思考其中细节:① 自适应滚动的内容是基于页面还是基于内部容器;② 组件是否可以组合使用;
分析:我们需要实现两个方向(向下拉动,向上滑动)上的拉动刷新,考虑完成 PullDownRefresh 和 PullUpRefresh 两个组件的编写。思考其中细节:
① 自适应滚动的内容是基于页面还是基于内部容器;
② 组件是否可以组合使用;
③ 状态提示loading如何设计;
④ loading开始与结束的时机,定时器规定时间?数据加载完结束?
目前实现
① 暂时未考虑页面和内部容器同时滑动的情况;
② 通过 props.children
传入需要拉动刷新的内容,两个组件可组合使用;
③ 通过一个 refreshing
状态变量来决定当前是否处于刷新状态;
④ 通过在 componentWillReceiveProps
生命周期钩子中接收新状态/数据来控制 loading 的结束,即 refreshing=false
依旧是模仿掘金主页的实现
预备知识
弄清楚元素的几个属性值(翻一下MDN吧)
- clientHeight:这个属性是只读属性,对于没有定义CSS或者内联布局盒子的元素为0,否则,它是 元素 内部的高度(单位像素),包含内边距,但不包括水平滚动条、边框和外边距
-
offsetHeight 是一个DOM属性。它有时被称为一个 元素 的物理/图形的尺寸,或是一个元素的边界框(border-box)的高度。
-
scrollTop 属性可以获取或设置一个 元素 的内容垂直滚动的像素数。部到视口可见内容(的顶部)的距离的度量。当一个元素的内容没有产生垂直方向的滚动条,那么它的 scrollTop 值为0
- scrollHeight:这个只读属性是一个 元素 内容高度的度量,包括由于溢出导致的视图中不可见内容。(属性将会对值四舍五入取整)。包括元素的padding,但不包括元素的border和margin。scrollHeight也包括
::before
和::after
这样的伪元素。 判断是否滚动到底部:element.scrollHeight - element.scrollTop === element.clientHeight
-
getBoundingClientRect()
方法返回 元素 的大小及其相对于视口的位置。
- 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项目实战(三)尝试实现一个拉动刷新组件》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 航班安全牵动人心,机场拉动智慧安防市场需求
- react-native-bsrefresh-list-view实现拉动刷新
- 「Flask实战」鱼书项目实战一
- 「Flask实战」鱼书项目实战三
- 「Flask实战」鱼书项目实战四
- 「Flask实战」鱼书项目实战六
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
MD5 加密
MD5 加密工具
RGB CMYK 转换工具
RGB CMYK 互转工具