react-native 自定义 下拉刷新 / 上拉加载更多 组件

react

1.封装 Scroller 组件

src/components/Scroller/index.js

/**

* 下拉刷新/上拉加载更多 组件(Scroller)

*/

import React, {Component} from \'react\';

import {

StyleSheet,

Text,

View,

ListView,

ActivityIndicator,

RefreshControl,

} from \'react-native\';

export default class Scroller extends Component {

// 构造函数

constructor(props) {

super(props);

this.state = {

//

}

}

render() {

const { dataSource, renderRow, isRefreshing } = this.props;

// console.log(this.props);

return (

<View style={styles.container}>

{/*列表数据*/}

<ListView

// 数据源

dataSource={dataSource}

// 从数据源(dataSource)中接受一条数据,以及它和它所在section的ID

renderRow={renderRow}

// 页头与页脚会在每次渲染过程中都重新渲染(允许在ListView底部增加一栏,便于显示加载动画)

renderFooter={this._renderFooter.bind(this)}

// 当所有的数据都已经渲染过,并且列表被滚动到距离最底部不足onEndReachedThreshold个像素的距离时调用

onEndReached={this._fetchMoreData.bind(this)}

// 调用onEndReached之前的临界值,单位是像素。(预加载)

onEndReachedThreshold={20}

// 隐藏右侧滚动条

showsVerticalScrollIndicator={false}

// finished warning : in next release ...

enableEmptySections={true}

// 自动调整迁移内容

// 导航栏或标签栏或工具栏不覆盖 Scrollview 内容

// 去除默认定位间距

automaticallyAdjustContentInsets={false}

// 下拉刷新

refreshControl={

<RefreshControl

// 是否刷新

refreshing={isRefreshing}

onRefresh={this._onRefresh.bind(this)}

tintColor={"#ff6600"}

title={"拼命加载中..."}

/>

}

/>

</View>

)

}

/**

* 下拉刷新

*/

_onRefresh() {

// console.log(\'下拉刷新\');

if (this.props.isRefreshing || !this._hasMore()) {

return

}

// 向后台发送 \'0\',告知刷新操作

this.props.fetchData(0);

}

/**

* 加 _ 代表私有方法

* 上拉加载更多

*/

_fetchMoreData() {

// console.log(\'上拉加载更多\');

/**

* this._hasMore() 验证还有更多数据

* isLoadingTail true/false 加载动画(菊花图)

*/

if (!this._hasMore() || this.props.isLoadingTail) {

return

}

let page = this.props.cachedResults.nextPage;

this.props.fetchData(page);

}

/**

* 验证还有更多数据

*/

_hasMore() {

return this.props.cachedResults.items.length !== this.props.cachedResults.items.total;

}

/**

* 底部加载动画 及 没有更多数据文本(ListView底部增加一栏,便于显示加载动画)

*/

_renderFooter() {

if (!this._hasMore() && this.props.cachedResults.total !== 0) {

return (

<View style={styles.loadingMore}>

<Text style={styles.loadingText}>没有更多了</Text>

</View>

)

}

if (!this.props.isLoadingTail) {

return (

<View style={styles.loadingMore}></View>

)

}

// 菊花图

return (

<ActivityIndicator style={styles.loadingMore}/>

)

}

}

// 样式

const styles = StyleSheet.create({

container: {

flex: 1,

backgroundColor: \'#F5FCFF\',

},

// 菊花图

loadingMore: {

marginVertical: 20

},

// 文案样式

loadingText: {

color: \'#777\',

textAlign: \'center\'

}

});

2.页面调用

/**

* 视频列表页

*/

import React, {Component} from \'react\';

import {

StyleSheet,

Text,

View,

ImageBackground,

ListView,

TouchableHighlight,

Alert,

Dimensions,

ActivityIndicator,

RefreshControl,

} from \'react-native\';

// 下拉刷新/上拉加载更多组件

import Scroller from \'../../components/Scroller\';

// 图标

import Icon from \'react-native-vector-icons/Ionicons\';

// item 组件

import CreationItem from \'../../components/CreationItem\';

import config from \'../../common/config\';

import request from \'../../common/request\';

let {width} = Dimensions.get("window");

// 缓存列表中所有数据

let cachedResults = {

nextPage: 1, // 下一页

items: [], // listview 数据(视频列表)

total: 0 // 总数

};

export default class List extends Component {

// 构造函数

constructor() {

super();

let ds = new ListView.DataSource({

// 比较两条数据是否是一样的,来判断数据是否发生改变

rowHasChanged: (r1, r2) => r1 !== r2

});

this.state = {

dataSource: ds.cloneWithRows([]),

isLoadingTail: false, // loading?

isRefreshing: false // refresh?

}

}

render() {

return (

<View style={styles.container}>

{/*顶部标题栏*/}

<View style={styles.header}>

<Text style={styles.headerTitle}>列表页面</Text>

</View>

{/*列表数据*/}

<Scroller

// 数据源

dataSource={this.state.dataSource}

// 渲染item(子组件)

renderRow={this._renderRow.bind(this)}

// 是否可以刷新

isRefreshing={this.state.isRefreshing}

// 是否可以加载更多

isLoadingTail={this.state.isLoadingTail}

// 请求数据

fetchData={this._fetchData.bind(this)}

// 缓存列表数据

cachedResults={cachedResults}

/>

</View>

)

}

// 生命周期-组件挂载完毕 请求数据

componentDidMount() {

this._fetchData(1);

}

// 请求数据

_fetchData(page) {

let that = this;

if (page !== 0) { // 加载更多操作

this.setState({

isLoadingTail: true

});

} else { // 刷新操作

this.setState({

isRefreshing: true

});

// 初始哈 nextPage

cachedResults.nextPage = 1;

}

request

.get(config.api.base + config.api.creations, {

accessToken: \'abc\'

})

// data 变化的新数据

.then((data) => {

if (data.success) {

// 保存原数据

let items = cachedResults.items.slice();

if (page !== 0) { // 加载更多操作

// 数组拼接

items = items.concat(data.data);

cachedResults.nextPage += 1;

} else { // 刷新操作

// 数据不变

items = data.data;

}

cachedResults.items = items; // 视频列表数据

cachedResults.total = data.total; // 总数

setTimeout(function () {

if (page !== 0) { // 加载更多操作

that.setState({

isLoadingTail: false,

dataSource: that.state.dataSource.cloneWithRows(cachedResults.items)

});

} else { // 刷次操作

that.setState({

isRefreshing: false,

dataSource: that.state.dataSource.cloneWithRows(cachedResults.items)

});

}

}, 1000);

}

})

.catch((error) => {

if (page !== 0) { // 上拉加载更多操作

this.setState({

isLoadingTail: false

});

} else {

this.setState({ // 刷新操作

isRefreshing: false

});

}

console.error(error);

});

}

// 列表 Item

_renderRow(row) {

const { navigation } = this.props;

return (

<CreationItem

navigation={navigation}

key={row.id} // 子组件唯一性

row={row}

/>

)

}

}

// 样式

const styles = StyleSheet.create({

container: {

flex: 1,

backgroundColor: \'#F5FCFF\',

},

// 头部样式

header: {

paddingTop: 25,

paddingBottom: 12,

backgroundColor: \'#ee735c\',

},

// 头部title样式

headerTitle: {

color: \'#fff\',

fontSize: 16,

textAlign: \'center\',

fontWeight: \'600\'

},

// 菊花图

loadingMore: {

marginVertical: 20

},

// 文案样式

loadingText: {

color: \'#777\',

textAlign: \'center\'

}

});

3.效果图

以上是 react-native 自定义 下拉刷新 / 上拉加载更多 组件 的全部内容, 来源链接: utcz.com/z/382813.html

回到顶部