React-Native 之 GD (十一)加载更多功能完善 及 跳转详情页

2023-03-14,,

1.加载更多功能完善

GDHome.js

/**
* 首页
*/
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
TouchableOpacity,
Image,
ListView,
Dimensions,
ActivityIndicator,
Modal, // 模态
AsyncStorage, // 缓存数据库(数据持久化)
} from 'react-native'; // 引入 下拉刷新组件
import {PullList} from 'react-native-pull';
// 导航器
import CustomerComponents, {
Navigator
} from 'react-native-deprecated-custom-components'; // 获取屏幕宽高
const {width, height} = Dimensions.get('window'); // 引入自定义导航栏组件
import CommunalNavBar from '../main/GDCommunalNavBar';
// 引入 近半小时热门组件
import HalfHourHot from './GDHalfHourHot';
// 引入 搜索页面组件
import Search from './GDSearch';
// 引入 cell
import CommunalHotCell from '../main/GDCommunalHotCell';
// 引入 空白页组件
import NoDataView from '../main/GDNoDataView'; // 引入 HTTP封装组件
import HTTPBase from '../http/HTTPBase'; export default class GDHome extends Component { // 构造
constructor(props) {
super(props);
// 初始状态
this.state = {
dataSource: new ListView.DataSource({rowHasChanged:(r1, r2) => r1 !== r2}), // 数据源 优化
loaded: false, // 用于判断是否显示空白页
isModal: false, // 用于判断模态的可见性
};
// 全局定义一个空数组用于存储列表数据
this.data = [];
// 绑定
this.loadData = this.loadData.bind(this);
this.loadMore = this.loadMore.bind(this);
} // 加载最新数据网络请求
loadData(resolve) { let params = {"count" : 10 }; HTTPBase.get('https://guangdiu.com/api/getlist.php', params)
.then((responseData) => {
          // 情况数据(刷新时)
this.data = []; // 拼接数据
this.data = this.data.concat(responseData.data); // 重新渲染
this.setState({
dataSource: this.state.dataSource.cloneWithRows(this.data),
loaded:true,
}); // 关闭刷新动画
if (resolve !== undefined){
setTimeout(() => {
resolve();
}, 1000);
} // 存储数组中最后一个元素的id
let cnlastID = responseData.data[responseData.data.length - 1].id;
AsyncStorage.setItem('cnlastID', cnlastID.toString()); // 只能存储字符或字符串 })
.catch((error) => { })
} // 加载更多数据的网络请求
loadMoreData(value) { let params = {
"count" : 10,
"sinceid" : value
}; HTTPBase.get('https://guangdiu.com/api/getlist.php', params)
.then((responseData) => { // 拼接数据
this.data = this.data.concat(responseData.data); // 重新渲染
this.setState({
dataSource: this.state.dataSource.cloneWithRows(this.data),
loaded:true,
}); // 存储数组中最后一个元素的id
let cnlastID = responseData.data[responseData.data.length - 1].id;
AsyncStorage.setItem('cnlastID', cnlastID.toString()); // 只能存储字符或字符串 })
.catch((error) => { })
} // 加载更多数据操作
loadMore() {
// 读取存储的id
AsyncStorage.getItem('cnlastID')
.then((value) => {
// 数据加载操作
this.loadMoreData(value);
})
} // 模态到近半小时热门
pushToHalfHourHot() {
this.setState({
isModal: true
})
} // 跳转到搜索页面
pushToSearch() {
this.props.navigator.push({
component: Search,
})
} // 安卓模态销毁模态
onRequestClose() {
this.setState({
isModal: false
})
} // 关闭模态
closeModal(data) {
this.setState({
isModal:data
})
} // 返回左边按钮
renderLeftItem() {
// 将组件返回出去
return(
<TouchableOpacity
onPress={() => {this.pushToHalfHourHot()}}
>
<Image source={{uri:'hot_icon_20x20'}} style={styles.navbarLeftItemStyle} />
</TouchableOpacity>
);
} // 返回中间按钮
renderTitleItem() {
return(
<TouchableOpacity>
<Image source={{uri:'navtitle_home_down_66x20'}} style={styles.navbarTitleItemStyle} />
</TouchableOpacity>
);
} // 返回右边按钮
renderRightItem() {
return(
<TouchableOpacity
// 跳转搜索页面
onPress={() => {this.pushToSearch()}}
>
<Image source={{uri:'search_icon_20x20'}} style={styles.navbarRightItemStyle} />
</TouchableOpacity>
);
} // ListView尾部
renderFooter() {
return (
<View style={{height: 100}}>
<ActivityIndicator />
</View>
);
} // 根据网络状态决定是否渲染 listView
renderListView() {
if(this.state.loaded === false) {
// 显示空白页
return(
<NoDataView />
);
}else{
return(
<PullList // 将ListView 改为 PullList
// 下拉刷新
onPullRelease={(resolve) => this.loadData(resolve)}
// 数据源 通过判断dataSource是否有变化,来判断是否要重新渲染
dataSource={this.state.dataSource}
renderRow={this.renderRow}
// 隐藏水平线
showsHorizontalScrollIndicator={false}
style={styles.listViewStyle}
initialListSize={5}
// 返回 listView 头部
renderHeader={this.renderHeader}
// 上拉加载更多
onEndReached={this.loadMore}
onEndReachedThreshold={60}
renderFooter={this.renderFooter}
/>
);
}
} // 返回每一行cell的样式
renderRow(rowData) {
// 使用cell组件
return(
<CommunalHotCell
image={rowData.image}
title={rowData.title}
/>
);
} // 生命周期 组件渲染完成 已经出现在dom文档里
componentDidMount() {
// 请求数据
this.loadData();
} render() {
return (
<View style={styles.container}>
{/* 初始化模态 */}
<Modal
animationType='slide' // 动画 底部弹窗
transparent={false} // 透明度
visible={this.state.isModal} // 可见性
onRequestClose={() => this.onRequestClose()} // 销毁
>
<HalfHourHot removeModal={(data) => this.closeModal(data)} />
</Modal> {/* 导航栏样式 */}
<CommunalNavBar
leftItem = {() => this.renderLeftItem()}
titleItem = {() => this.renderTitleItem()}
rightItem = {() => this.renderRightItem()}
/> {/* 根据网络状态决定是否渲染 listView */}
{this.renderListView()}
</View>
);
}
} const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
},
navbarLeftItemStyle: {
width:20,
height:20,
marginLeft:15,
},
navbarTitleItemStyle: {
width:66,
height:20,
},
navbarRightItemStyle: {
width:20,
height:20,
marginRight:15,
}, listViewStyle: {
width:width,
},
});

核心代码:

// 加载最新数据网络请求
loadData(resolve) { let params = {"count" : 10 }; HTTPBase.get('https://guangdiu.com/api/getlist.php', params)
.then((responseData) => {
          // 清空数据(刷新时)
this.data = []; // 拼接数据
this.data = this.data.concat(responseData.data); // 重新渲染
this.setState({
dataSource: this.state.dataSource.cloneWithRows(this.data),
loaded:true,
}); // 关闭刷新动画
if (resolve !== undefined){
setTimeout(() => {
resolve();
}, 1000);
} // 存储数组中最后一个元素的id
let cnlastID = responseData.data[responseData.data.length - 1].id;
AsyncStorage.setItem('cnlastID', cnlastID.toString()); // 只能存储字符或字符串 })
.catch((error) => { })
} // 加载更多数据的网络请求
loadMoreData(value) { let params = {
"count" : 10,
"sinceid" : value
}; HTTPBase.get('https://guangdiu.com/api/getlist.php', params)
.then((responseData) => { // 拼接数据
this.data = this.data.concat(responseData.data); // 重新渲染
this.setState({
dataSource: this.state.dataSource.cloneWithRows(this.data),
loaded:true,
}); // 存储数组中最后一个元素的id
let cnlastID = responseData.data[responseData.data.length - 1].id;
AsyncStorage.setItem('cnlastID', cnlastID.toString()); // 只能存储字符或字符串 })
.catch((error) => { })
} // 加载更多数据操作
loadMore() {
// 读取存储的id
AsyncStorage.getItem('cnlastID')
.then((value) => {
// 数据加载操作
this.loadMoreData(value);
})
}

2.详情页

(1)Cell 点击实现

我们回到主页这边来实现以下 cell 的点击,需要注意的是对 row 进行绑定操作,不然会找不到当前的 this。

// 绑定
renderRow={this.renderRow.bind(this)}

接着来看下 renderRow 方法实现:

// 返回每一行cell的样式
renderRow(rowData) {
return(
<TouchableOpacity
onPress={() => this.pushToDetail(rowData.id)}
>
<CommunalHotCell
image={rowData.image}
title={rowData.title}
/>
</TouchableOpacity>
);
}

再来看下 pushToDetail 方法实现,params意思就是将 url 参数传递到 CommunalDetail 组件:

// 跳转到详情页
pushToDetail(value) {
this.props.navigator.push({
component:CommunalDetail,
params: {
url: 'https://guangdiu.com/api/showdetail.php' + '?' + 'id=' + value
}
})
}

(2)详情页

既然我们已经保存了 id 那么就可以来做详情页了,当我们点击 cell 的时候,需要跳转到对应的 详情页 。

先来看详情页的实现:

GDCommunalDetail.js

/**
* 详情页
*/
import React, { Component, PropTypes } from 'react';
import {
StyleSheet,
WebView,
View,
Text,
TouchableOpacity,
DeviceEventEmitter,
} from 'react-native'; // 导航器
import CustomerComponents, {
Navigator
} from 'react-native-deprecated-custom-components'; // 引入自定义导航栏组件
import CommunalNavBar from './GDCommunalNavBar'; export default class GDCommunalDetail extends Component { // 创建属性,便于外部传值使用
static propTypes = {
uri:PropTypes.string,
}; // 返回
pop() {
this.props.navigator.pop();
} // 返回左边按钮
renderLeftItem() {
return(
<TouchableOpacity
onPress={() => {this.pop()}}
>
<Text>返回</Text>
</TouchableOpacity>
);
} componentWillMount() {
// 向GDMain.js 发送通知 隐藏tabBar
DeviceEventEmitter.emit('isHiddenTabBar', true);
} componentWillUnmount() {
// 向GDMain.js 发送通知 显示tabBar
DeviceEventEmitter.emit('isHiddenTabBar', false);
} render() {
return(
<View style={styles.container}>
{/* 导航栏 */}
<CommunalNavBar
leftItem = {() => this.renderLeftItem()}
/> {/* 初始化WebView */}
<WebView
style={styles.webViewStyle}
source={{uri:this.props.url, method: 'GET' }}
javaScriptEnabled={true}
domStorageEnabled={true}
scalesPageToFit={false}
/>
</View>
);
}
} const styles = StyleSheet.create({
container: {
flex:1
}, webViewStyle: {
flex: 1
}
});

效果图

3. 调用

GDHome.js

/**
* 首页
*/
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
TouchableOpacity,
Image,
ListView,
Dimensions,
ActivityIndicator,
Modal, // 模态
AsyncStorage, // 缓存数据库(数据持久化)
} from 'react-native'; // 引入 下拉刷新组件
import {PullList} from 'react-native-pull';
// 导航器
import CustomerComponents, {
Navigator
} from 'react-native-deprecated-custom-components'; // 获取屏幕宽高
const {width, height} = Dimensions.get('window'); // 引入自定义导航栏组件
import CommunalNavBar from '../main/GDCommunalNavBar';
// 引入 近半小时热门组件
import HalfHourHot from './GDHalfHourHot';
// 引入 搜索页面组件
import Search from './GDSearch';
// 引入 cell
import CommunalHotCell from '../main/GDCommunalHotCell';
// 引入 详情页 组件
import CommunalDetail from '../main/GDCommunalDetail';
// 引入 空白页组件
import NoDataView from '../main/GDNoDataView'; // 引入 HTTP封装组件
import HTTPBase from '../http/HTTPBase'; export default class GDHome extends Component { // 构造
constructor(props) {
super(props);
// 初始状态
this.state = {
dataSource: new ListView.DataSource({rowHasChanged:(r1, r2) => r1 !== r2}), // 数据源 优化
loaded: false, // 用于判断是否显示空白页
isModal: false, // 用于判断模态的可见性
};
// 全局定义一个空数组用于存储列表数据
this.data = [];
// 绑定
this.loadData = this.loadData.bind(this);
this.loadMore = this.loadMore.bind(this);
} // 加载最新数据网络请求
loadData(resolve) { let params = {"count" : 10 }; HTTPBase.get('https://guangdiu.com/api/getlist.php', params)
.then((responseData) => {
          // 清空数据
this.data = []; // 拼接数据
this.data = this.data.concat(responseData.data); // 重新渲染
this.setState({
dataSource: this.state.dataSource.cloneWithRows(this.data),
loaded:true,
}); // 关闭刷新动画
if (resolve !== undefined){
setTimeout(() => {
resolve();
}, 1000);
} // 存储数组中最后一个元素的id
let cnlastID = responseData.data[responseData.data.length - 1].id;
AsyncStorage.setItem('cnlastID', cnlastID.toString()); // 只能存储字符或字符串 })
.catch((error) => { })
} // 加载更多数据的网络请求
loadMoreData(value) { let params = {
"count" : 10,
"sinceid" : value
}; HTTPBase.get('https://guangdiu.com/api/getlist.php', params)
.then((responseData) => { // 拼接数据
this.data = this.data.concat(responseData.data); // 重新渲染
this.setState({
dataSource: this.state.dataSource.cloneWithRows(this.data),
loaded:true,
}); // 存储数组中最后一个元素的id
let cnlastID = responseData.data[responseData.data.length - 1].id;
AsyncStorage.setItem('cnlastID', cnlastID.toString()); // 只能存储字符或字符串 })
.catch((error) => { })
} // 加载更多数据操作
loadMore() {
// 读取存储的id
AsyncStorage.getItem('cnlastID')
.then((value) => {
// 数据加载操作
this.loadMoreData(value);
})
} // 模态到近半小时热门
pushToHalfHourHot() {
this.setState({
isModal: true
})
} // 跳转到搜索页面
pushToSearch() {
this.props.navigator.push({
component: Search,
})
} // 安卓模态销毁模态
onRequestClose() {
this.setState({
isModal: false
})
} // 关闭模态
closeModal(data) {
this.setState({
isModal:data
})
} // 返回左边按钮
renderLeftItem() {
// 将组件返回出去
return(
<TouchableOpacity
onPress={() => {this.pushToHalfHourHot()}}
>
<Image source={{uri:'hot_icon_20x20'}} style={styles.navbarLeftItemStyle} />
</TouchableOpacity>
);
} // 返回中间按钮
renderTitleItem() {
return(
<TouchableOpacity>
<Image source={{uri:'navtitle_home_down_66x20'}} style={styles.navbarTitleItemStyle} />
</TouchableOpacity>
);
} // 返回右边按钮
renderRightItem() {
return(
<TouchableOpacity
// 跳转搜索页面
onPress={() => {this.pushToSearch()}}
>
<Image source={{uri:'search_icon_20x20'}} style={styles.navbarRightItemStyle} />
</TouchableOpacity>
);
} // ListView尾部
renderFooter() {
return (
<View style={{height: 100}}>
<ActivityIndicator />
</View>
);
} // 根据网络状态决定是否渲染 listView
renderListView() {
if(this.state.loaded === false) {
// 显示空白页
return(
<NoDataView />
);
}else{
return(
<PullList // 将ListView 改为 PullList
// 下拉刷新
onPullRelease={(resolve) => this.loadData(resolve)}
// 数据源 通过判断dataSource是否有变化,来判断是否要重新渲染
dataSource={this.state.dataSource}
renderRow={this.renderRow.bind(this)}
// 隐藏水平线
showsHorizontalScrollIndicator={false}
style={styles.listViewStyle}
initialListSize={5}
// 返回 listView 头部
renderHeader={this.renderHeader}
// 上拉加载更多
onEndReached={this.loadMore}
onEndReachedThreshold={60}
renderFooter={this.renderFooter}
/>
);
}
} // 通过id 跳转详情页
pushToDetail(value) {
this.props.navigator.push({
component:CommunalDetail,
params: {
url: 'https://guangdiu.com/api/showdetail.php' + '?' + 'id=' + value
}
})
} // 返回每一行cell的样式
renderRow(rowData) {
// 使用cell组件
return(
<TouchableOpacity
// 给每一个cell添加点击事件
onPress={() => this.pushToDetail(rowData.id)}
>
<CommunalHotCell
image={rowData.image}
title={rowData.title}
/>
</TouchableOpacity>
);
} // 生命周期 组件渲染完成 已经出现在dom文档里
componentDidMount() {
// 请求数据
this.loadData();
} render() {
return (
<View style={styles.container}>
{/* 初始化模态 */}
<Modal
animationType='slide' // 动画 底部弹窗
transparent={false} // 透明度
visible={this.state.isModal} // 可见性
onRequestClose={() => this.onRequestClose()} // 销毁
>
<Navigator
initialRoute={{
name:'halfHourHot',
component:HalfHourHot
}} renderScene={(route, navigator) => {
let Component = route.component;
return <Component
removeModal={(data) => this.closeModal(data)}
{...route.params}
navigator={navigator} />
}} />
</Modal> {/* 导航栏样式 */}
<CommunalNavBar
leftItem = {() => this.renderLeftItem()}
titleItem = {() => this.renderTitleItem()}
rightItem = {() => this.renderRightItem()}
/> {/* 根据网络状态决定是否渲染 listView */}
{this.renderListView()}
</View>
);
}
} const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
},
navbarLeftItemStyle: {
width:20,
height:20,
marginLeft:15,
},
navbarTitleItemStyle: {
width:66,
height:20,
},
navbarRightItemStyle: {
width:20,
height:20,
marginRight:15,
}, listViewStyle: {
width:width,
},
});

GDHalfHourHot.js

/**
* 近半小时热门
*/
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
TouchableOpacity,
Image,
ListView,
Dimensions,
DeviceEventEmitter,
} from 'react-native'; // 获取屏幕宽高
const {width, height} = Dimensions.get('window'); // 引入自定义导航栏组件
import CommunalNavBar from '../main/GDCommunalNavBar';
// 引入 cell
import CommunalHotCell from '../main/GDCommunalHotCell';
// 引入 详情页 组件
import CommunalDetail from '../main/GDCommunalDetail';
// 引入 空白页组件
import NoDataView from '../main/GDNoDataView';
// 引入 下拉刷新组件
import {PullList} from 'react-native-pull'; // 引入 HTTP封装组件
import HTTPBase from '../http/HTTPBase'; export default class GDHalfHourHot extends Component { // 构造
constructor(props) {
super(props);
// 初始状态
this.state = {
dataSource: new ListView.DataSource({rowHasChanged:(r1, r2) => r1 !== r2}), // 数据源 优化
loaded: false, // 用于判断是否显示空白页
};
// 绑定
this.fetchData = this.fetchData.bind(this);
} // 提供参数出去,便于外部调用
static defaultProps = {
removeModal:{}
} // 网络请求
fetchData(resolve) { HTTPBase.get('http://guangdiu.com/api/gethots.php')
.then((responseData) => { // 处理数据
// 修改dataSource的值
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData.data),
loaded:true,
});
// 关闭下拉刷新动画
if (resolve !== undefined){
// 使用定时器 延时关闭动画
setTimeout(() => {
resolve(); // 关闭动画
}, 1000);
}
})
.catch((error) => { })
} popToHome(data) {
// 向外部传值
this.props.removeModal(data);
} // 返回中间按钮
renderTitleItem() {
return(
<Text style={styles.navbarTitleItemStyle}>近半小时热门</Text>
);
} // 返回右边按钮
renderRightItem() {
return(
<TouchableOpacity
onPress={() => {this.popToHome(false)}}
>
<Text style={styles.navbarRightItemStyle}>关闭</Text>
</TouchableOpacity>
);
} // 根据网络状态决定是否渲染 listView
renderListView() {
if(this.state.loaded === false) {
// 显示空白页
return(
<NoDataView />
);
}else{
return(
<PullList // 将ListView 改为 PullList
// 下拉刷新
onPullRelease={(resolve) => this.fetchData(resolve)}
// 数据源 通过判断dataSource是否有变化,来判断是否要重新渲染
dataSource={this.state.dataSource}
renderRow={this.renderRow.bind(this)}
// 隐藏水平线
showsHorizontalScrollIndicator={false}
style={styles.listViewStyle}
initialListSize={5}
// 返回 listView 头部
renderHeader={this.renderHeader}
/>
);
}
} // 返回 listView 头部
renderHeader() {
return(
<View style={styles.headerPromptStyle}>
<Text>根据每条折扣的点击进行统计,每5分钟更新一次</Text>
</View>
);
} // 通过id 跳转详情页
pushToDetail(value) {
this.props.navigator.push({
component:CommunalDetail,
params: {
url: 'http://guangdiu.com/api/showdetail.php' + '?' + 'id=' + value
}
})
} // 返回每一行cell的样式
renderRow(rowData) {
// 使用cell组件
return(
<TouchableOpacity
// 给每一个cell添加点击事件
onPress={() => this.pushToDetail(rowData.id)}
>
<CommunalHotCell
image={rowData.image}
title={rowData.title}
/>
</TouchableOpacity>
);
} componentWillMount() {
// 向GDMain.js 发送通知 隐藏tabBar
DeviceEventEmitter.emit('isHiddenTabBar', true);
} componentWillUnmount() {
// 向GDMain.js 发送通知 显示tabBar
DeviceEventEmitter.emit('isHiddenTabBar', false);
} // 生命周期 组件渲染完成 已经出现在dom文档里
componentDidMount() {
// 请求数据
this.fetchData();
} render() {
return (
<View style={styles.container}>
{/* 导航栏样式 */}
<CommunalNavBar
titleItem = {() => this.renderTitleItem()}
rightItem = {() => this.renderRightItem()}
/> {/* 根据网络状态决定是否渲染 listView */}
{this.renderListView()}
</View>
);
}
} const styles = StyleSheet.create({
container: {
flex:1,
alignItems: 'center',
}, navbarTitleItemStyle: {
fontSize:17,
color:'black',
marginLeft:50
},
navbarRightItemStyle: {
fontSize:17,
color:'rgba(123,178,114,1.0)',
marginRight:15
}, headerPromptStyle: {
height:44,
width:width,
backgroundColor:'rgba(239,239,239,0.5)',
justifyContent:'center',
alignItems:'center'
}, listViewStyle: {
width:width,
},
});

.

React-Native 之 GD (十一)加载更多功能完善 及 跳转详情页的相关教程结束。

《React-Native 之 GD (十一)加载更多功能完善 及 跳转详情页.doc》

下载本文的Word格式文档,以方便收藏与打印。