XtnScroll 组件,先看一下效果图
下拉的效果
上拉的效果
- 以前都是用Vue–XtnScroll、Angular4–XtnScroll来实现的刷新组件今天说说React怎么实现。其实这三种框架里用到的方法都是一样的,只是每个里面都有自己的语法特性不一样,所以实现起来大同小意了。
创建组件步骤
目录结构如下图所示
- scss 样式文件
- svg 加载动画
- XtnScroll.js真正的文件
XtnScroll.js文件
import React, { Component, PropTypes } from 'react';
import { Utility } from 'components';
const styles = require('./scss/XtnScroll.scss');
/**
* <XtnScroll
* RefreshComplete={RefreshComplete}
* NextDataComplete={NextDataComplete}
* onRefresh={()=>{....}}
* onNextData={()=>{....}}
* />
*/
export default class XtnScroll extends Component {
}
属性
static propTypes = {
children: PropTypes.any, // 子项
Percentage: PropTypes.number, // 百分比
RefreshComplete: PropTypes.bool, // 刷新完成
NextDataComplete: PropTypes.bool, // 加载更多数据完成
onRefresh: PropTypes.func, // 刷新操作
onNextData: PropTypes.func, // 更多数据
}
render方法
- 里面三个主要方法 onTouchStart、onTouchEnd、onTouchMove。分别对应的三个事件__HandlerStart、__HandlerEnd、__HandlerMove。
render() {
const { RefreshComplete, NextDataComplete } = this.props;
return (
<div ref="divXtnScroll" className={styles.refreshCss} style={this.__GetStyle()}
onTouchStart={this.__HandlerStart.bind(this)}
onTouchEnd={this.__HandlerEnd.bind(this)}
onTouchMove={this.__HandlerMove.bind(this)}
>
{
!LoadType ?
<div className={styles.refreshAnimation + ' ' + (RefreshComplete ? styles.hideRefresh : styles.showRefresh)}>
<div></div>
</div>
:
<div ref="divOtherAni" className={styles.otherAni}>
<div>
<div ref="divLoading"></div>
<div ref="divOtherAniDesc"></div>
</div>
</div>
}
<div className={styles.content} ref="divContent">
{this.props.children}
</div>
<div
className={styles.loadingMoreDataAnimation + ' ' + (NextDataComplete ? styles.hideLoadMore : styles.showLoadMore)}>
<div className={styles.spinner}>
<div className={styles.bounce1}></div>
<div className={styles.bounce2}></div>
<div className={styles.bounce3}></div>
</div>
</div>
</div>
);
}
__HandlerStart 开始移动方法
- 这主要是记录当前的位置信息
/**
* 开始移动
*
* @param {any} event
*
* @memberOf Refresh
*/
__HandlerStart(event) {
const { clientX, clientY } = event.touches[0];
this.state.startX = clientX;
this.state.startY = clientY;
}
__HandlerMove 开始移动操作。
__HandlerMove(event) {
this.__ProcessAniStart(event);
// android 版本小 5的话,是没有 end事件的。只有start,和move事件。
const { version } = Utility.$androidVersion() || {};
if (!version) {
return;
}
if (version > '5.0') {
return;
}
this.__HandlerEnd(event);
}
- __ProcessAniStart 主要是用于判断向下拉显示相应的字信息。
__ProcessAniStart(event) {
const { LoadType, RefreshComplete, NextDataComplete } = this.props;
if (!LoadType || !RefreshComplete || !NextDataComplete) {
return;
}
const { clientY } = event.changedTouches[0];
this.state.moveY = clientY;
const { startY } = this.state;
const abs = clientY - startY;
const { divContent, divOtherAni, divOtherAniDesc, divLoading } = this.refs;
const __MaxValue = 200;
if (abs > 0) {
divLoading.classList.remove(styles.loading);
divOtherAni.classList.remove(styles.hide);
if (abs <= __MaxValue) {
const __3d = 'translate3d(0px, ' + abs + 'px, 0px)';
divContent.style.transform = __3d;
divContent.style.webkitTransform = __3d;
divOtherAni.style.transform = __3d;
divOtherAni.style.webkitTransform = __3d;
divOtherAniDesc.innerHTML = '下拉刷新';
}
if (abs > __MaxValue) {
divOtherAniDesc.innerHTML = '释放立即更新';
}
}
}
__HandlerEnd 移动结束事件
- 移动结束这个时候要判断移动的方向,向上或下拉,还是向左右滑动。判断好相应的方法后,通知父级组件,调用相应的方法了。
/**
* 移动结束
*
* @param {any} event
* @returns
*
* @memberOf Refresh
*/
__HandlerEnd(event) {
this.__ProcessSlideEnd();
const { RefreshComplete, NextDataComplete } = this.props;
if (!RefreshComplete || !NextDataComplete) {
return;
}
const { startX, startY } = this.state;
const { clientY, clientX } = event.changedTouches[0];
const xes = clientX - startX;
const yes = clientY - startY;
const absXes = Math.abs(xes);
const absYes = Math.abs(yes);
if (absXes < 10 && absYes < 10) {
return;
}
this.__ProcessAniEnd();
if (xes > 0) { // 右
if (yes > 0) {// 向下
// 判断主向
if (absXes > absYes) {// 向右。
this.__HandlerSlideRight();
} else {// 向下。
this.__HandlerRefresh();
}
} else {// 向上
if (absXes > absYes) {// 向右。
this.__HandlerSlideRight();
} else {// 向上。
this.__HandlerNextData();
}
}
} else {// 左边
if (yes > 0) {// 向下
if (absXes > absYes) {// 向左。
this.__HandlerSlideLeft();
} else {// 向下。
this.__HandlerRefresh();
}
} else {// 向上
if (absXes > absYes) {
this.__HandlerSlideLeft();
} else {
this.__HandlerNextData();
}
}
}
}
- __HandlerNextData 事件,判断是否要通知父级组件调用获取下一页数据的接口。
/**
* 下一页数据
*
* @returns
*
* @memberOf Refresh
*/
__HandlerNextData() {
const { onNextData, NextDataComplete } = this.props;
if (!Utility.isFunction(onNextData) || NextDataComplete === false) {
return;
}
const Percentage = this.props.Percentage || 1;
const __bodyScrollTop = document.body.scrollTop || document.documentElement.scrollTop || window.pageYOffset;
const __bodyScrollHeight = document.body.scrollHeight || document.documentElement.scrollHeight;
const __differValue = ((__bodyScrollHeight - __bodyScrollTop - screen.height) / __bodyScrollHeight) * 100;
if (__differValue > (Percentage < 2 ? 2 : Percentage)) {
return;
}
onNextData();
}
. __HandlerRefresh 判断是否要告诉父级组件要刷新数据操作
/**
* 刷新
*
* @returns
*
* @memberOf Refresh
*/
__HandlerRefresh() {
const divXtnScroll = this.refs.divXtnScroll;
const body = document.body;
const __differenceValue = body.scrollHeight - divXtnScroll.scrollHeight;
const __bodyScrollTop = body.scrollTop;
if (__bodyScrollTop > __differenceValue) {
return;
}
const { onRefresh, RefreshComplete } = this.props;
if (!Utility.isFunction(onRefresh) || RefreshComplete === false) {
return;
}
onRefresh();
}

本文介绍如何在React中实现带有下拉刷新和加载更多功能的XtnScroll组件。通过监听触摸事件,实现数据刷新及加载,适用于移动端应用。
323

被折叠的 条评论
为什么被折叠?



