React-Native 之 GD (十三)数据持久化(realm) 及 公共Cell

1.数据持久化

数据持久化是移动端的一个重要部分,刚发现 Realm 原来已经支持 React-Native 了

步骤一: 引入 realm

$ npm install realm --save

步骤二: 添加 Realm 与 工程的链接

react-native >= 0.31.0

react-native link realm

react-native  <  0.31.0

rnpm link realm

 首先,在为了方便使用,也为了减少第三方框架对工程的 “污染”,我们需要对框架进行一次 基础 的封装。

realmStorage.js

/**
 * 数据持久化
 * 本地数据存储
 */
// 提供变量,便于外部调用
var RealmBase = {};

import Realm from 'realm';

// 创建数据表(首页)
const HomeSchame = {
    name:'HomeData',
    properties:{
        id:'int',
        title:'string',
        image:'string',
        mall:'string', // 商城平台
        pubtime:'string',
        fromsite:'string',
    }
};

// 创建数据表(海淘)
const HTSchame = {
    name:'HTData',
    properties:{
        id:'int',
        title:'string',
        image:'string',
        mall:'string',
        pubtime:'string',
        fromsite:'string',
    }
};

// 初始化realm
let realm = new Realm({schema:[HomeSchame, HTSchame]});

// 增加
RealmBase.create = function (schame, data) {
    realm.write(() => {
        for (let i = 0; i<data.length; i++) {
            let temp = data[i];
            realm.create(schame, {id:temp.id, title:temp.title, image:temp.image, mall:temp.mall, pubtime:temp.pubtime, fromsite:temp.fromsite});
        }
    })
}

// 查询全部数据
RealmBase.loadAll = function (schame) {
    return realm.objects(schame);
}

// 条件查询
RealmBase.filtered = function (schame, filtered) {
    // 获取对象
    let objects = realm.objects(schame);
    // 筛选
    let object = objects.filtered(filtered);

    if (object) {   // 有对象
        return object;
    }else {
        return '未找到数据';
    }
}

// 删除所有数据
RealmBase.removeAllData = function (schame) {
    realm.write(() => {
        // 获取对象
        let objects = realm.objects(schame);
        // 删除表
        realm.delete(objects);
    })
}

global.RealmBase = RealmBase;

GDMain.js 调用

// 引入 HTTP封装组件
import HTTP from '../http/HTTPBase';

// 引入 本地数据存储封装组件 (数据持久化)
import RealmStorage from '../storage/realmStorage';

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 '../main/GDSearch';
// 引入 cell
import CommunalHotCell from '../main/GDCommunalHotCell';
// 引入 详情页 组件
import CommunalDetail from '../main/GDCommunalDetail';
// 引入 空白页组件
import NoDataView from '../main/GDNoDataView';

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());  // 只能存储字符或字符串

                // 首页存储数组中第一个元素的id
                let cnfirstID = responseData.data[0].id;
                AsyncStorage.setItem('cnfirstID', cnfirstID.toString());

                 // 清除本地存储的数据
                RealmBase.removeAllData('HomeData');

                // 存储数据到本地
                RealmBase.create('HomeData', responseData.data); // 向数据表存储数据
            })
            .catch((error) => {
                // 数据加载失败,拿到本地存储的数据,展示出来,如果没有存储,那就显示无数据页面
                this.data = RealmBase.loadAll('HomeData'); // 从数据表提取数据

                // 重新渲染
                this.setState({
                    dataSource: this.state.dataSource.cloneWithRows(this.data),
                    loaded:true,
                });
            })
    }

    // 加载更多数据的网络请求
    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,
    },
});

核心代码:

// 加载最新数据网络请求
    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());  // 只能存储字符或字符串

                // 首页存储数组中第一个元素的id
                let cnfirstID = responseData.data[0].id;
                AsyncStorage.setItem('cnfirstID', cnfirstID.toString());

                 // 清除本地存储的数据
                RealmBase.removeAllData('HomeData');

                // 存储数据到本地
                RealmBase.create('HomeData', responseData.data); // 向数据表存储数据
            })
            .catch((error) => {
                // 数据加载失败,拿到本地存储的数据,展示出来,如果没有存储,那就显示无数据页面
                this.data = RealmBase.loadAll('HomeData'); // 从数据表提取数据

                // 重新渲染
                this.setState({
                    dataSource: this.state.dataSource.cloneWithRows(this.data),
                    loaded:true,
                });
            })
    }

 

2.因为 realm 下载的内容过大,不易上传至 github 需要在 .gitignore 上设置 忽略

/node_modules/realm/*

 

3.设置 ListView 默认显示条数,避免列表下出现空白

4.自定义详情cell

首先,还是一样,我们先来创建 GDCommunalCell 文件,并且我们将前面 自定义cell 里面的内容 copy 一下,放到这个文件中,并进行相应修改:

GDCommunalCell.js

/**
 * 公共 Cell
 */
import React, { Component, PropTypes } from 'react';
import {
    StyleSheet,
    Text,
    View,
    Dimensions,
    Platform,
    Image,
} from 'react-native';

// 获取屏幕宽高
const {width, height} = Dimensions.get('window');

export default class GDCommunalCell extends Component {

	// 定义成员属性
	static propTypes = {
        image:PropTypes.string,
        title:PropTypes.string,
        mall:PropTypes.string, // 平台
        pubTime:PropTypes.string, // 时间
        fromSite:PropTypes.string, // 来源
    };

    renderDate(pubTime, fromSite) {

        // 时间差的计算
        let minute = 1000 * 60;     // 1分钟
        let hour = minute * 60;     // 1小时
        let day = hour * 24;        // 1天
        let week = day * 7;         // 1周
        let month = day * 30;       // 1个月

        // 计算时间差
        let now = new Date().getTime();     // 获取当前时间
        let diffValue = now - Date.parse(pubTime.replace(/-/gi, "/"));

        if (diffValue < 0) return;

        let monthC = diffValue/month;   // 相差了几个月
        let weekC = diffValue/week;     // 相差几周
        let dayC = diffValue/day;       // 相差几天
        let hourC = diffValue/hour      // 相差几小时
        let minuteC = diffValue/minute; // 相差几分钟

        let result;

        if (monthC >= 1) {
            result = parseInt(monthC) + "月前";
        }else if (weekC >= 1) {
            result = parseInt(weekC) + "周前";
        }else if (dayC >= 1) {
            result = parseInt(dayC) + "天前";
        }else if (hourC >= 1) {
            result = parseInt(hourC) + "小时前";
        }else if (minuteC >= 1) {
            result = parseInt(minuteC) + "分钟前";
        }else result = "刚刚";

        return result + ' · ' + fromSite;

    }

    render() {
        return (
            <View style={styles.container}>
                {/* 左边图片 */}
                <Image source={{uri:this.props.image === '' ? 'defaullt_thumb_83x83' : this.props.image}} style={styles.imageStyle} />
                {/* 中间 */}
                <View style={styles.centerViewStyle}>
                    {/* 标题 */}
                    <View>
                        <Text numberOfLines={3} style={styles.titleStyle}>{this.props.title}</Text>
                    </View>
                    {/* 详情 */}
                    <View style={styles.detailViewStyle}>
                        {/* 平台 */}
                        <Text style={styles.detailMallStyle}>{this.props.mall}</Text>
                        {/* 时间 + 来源 */}
                        <Text style={styles.timeStyle}>{this.renderDate(this.props.pubTime, this.props.fromSite)}</Text>
                    </View>

                </View>
                {/* 右边的箭头 */}
                <Image source={{uri:'icon_cell_rightArrow'}} style={styles.arrowStyle} />
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flexDirection:'row',
        alignItems:'center',
        justifyContent:'space-between',
        backgroundColor:'white',
        height:100,
        width:width,
        borderBottomWidth:0.5,
        borderBottomColor:'gray',
        marginLeft:15

    },

    imageStyle: {
        width:70,
        height:70,
    },

    centerViewStyle: {
        height:70,
        justifyContent:'space-around',
    },

    titleStyle: {
        width:width * 0.65,
    },

    detailViewStyle: {
        flexDirection:'row',
        justifyContent:'space-between',
        alignItems:'center'
    },
    detailMallStyle: {
        fontSize:12,
        color:'green',
    },
    timeStyle: {
        fontSize:12,
        color:'gray',
    },

    arrowStyle: {
        width:10,
        height:10,
        marginRight:30,
    }
});

 

GDHome.js  及 GDHt.js 调用

// 引入 公共cell
import CommunalCell from '../main/GDCommunalCell';

 

 

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 '../main/GDSearch';
// 引入 公共cell
import CommunalCell from '../main/GDCommunalCell';
// 引入 详情页 组件
import CommunalDetail from '../main/GDCommunalDetail';
// 引入 空白页组件
import NoDataView from '../main/GDNoDataView';

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());  // 只能存储字符或字符串

                // 首页存储数组中第一个元素的id
                let cnfirstID = responseData.data[0].id;
                AsyncStorage.setItem('cnfirstID', cnfirstID.toString());

                // // 清除本地存储的数据
                // RealmBase.removeAllData('HomeData');

                // // 存储数据到本地
                // RealmBase.create('HomeData', responseData.data); // 向数据表存储数据
            })
            .catch((error) => {
                // // 数据加载失败,拿到本地存储的数据,展示出来,如果没有存储,那就显示无数据页面
                // this.data = RealmBase.loadAll('HomeData'); // 从数据表提取数据

                // // 重新渲染
                // this.setState({
                //     dataSource: this.state.dataSource.cloneWithRows(this.data),
                //     loaded:true,
                // });
            })
    }

    // 加载更多数据的网络请求
    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={7}  // 默认渲染数据条数
                    // 返回 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)}
            >
                <CommunalCell
                    image={rowData.image}
                    title={rowData.title}
                    mall={rowData.mall}  // 平台
                    pubTime={rowData.pubtime}  // 时间
                    fromSite={rowData.fromsite}  // 来源
                />
            </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,
    },
});

GDHt.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 USHalfHourHot from './GDUSHalfHourHot';
// 引入 搜索页面组件
import Search from '../main/GDSearch';
// 引入 cell
import CommunalCell from '../main/GDCommunalCell';
// 引入 详情页 组件
import CommunalDetail from '../main/GDCommunalDetail';
// 引入 空白页组件
import NoDataView from '../main/GDNoDataView';

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,
            "country" : "us"
        };

        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 uslastID = responseData.data[responseData.data.length - 1].id;
                AsyncStorage.setItem('uslastID', uslastID.toString());  // 只能存储字符或字符串

                // 首页存储数组中第一个元素的id
                let usfirstID = responseData.data[0].id;
                AsyncStorage.setItem('usfirstID', usfirstID.toString());
                
                // // 清除本地存储的数据
                // RealmBase.removeAllData('HomeData');

                // // 存储数据到本地
                // RealmBase.create('HomeData', responseData.data); // 向数据表存储数据
            })
            .catch((error) => {
                // // 数据加载失败,拿到本地存储的数据,展示出来,如果没有存储,那就显示无数据页面
                // this.data = RealmBase.loadAll('HomeData'); // 从数据表提取数据

                // // 重新渲染
                // this.setState({
                //     dataSource: this.state.dataSource.cloneWithRows(this.data),
                //     loaded:true,
                // });
            })
    }

    // 加载更多数据的网络请求
    loadMoreData(value) {

        let params = {
            "count" : 10,
            "country" : "us",
            "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 uslastID = responseData.data[responseData.data.length - 1].id;
                AsyncStorage.setItem('uslastID', uslastID.toString());  // 只能存储字符或字符串

            })
            .catch((error) => {

            })
    }

    // 加载更多数据操作
    loadMore() {
        // 读取存储的id
        AsyncStorage.getItem('uslastID')
            .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={7}
                    // 返回 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)}
            >
                <CommunalCell
                    image={rowData.image}
                    title={rowData.title}
                    mall={rowData.mall}  // 平台
                    pubTime={rowData.pubtime}  // 时间
                    fromSite={rowData.fromsite}  // 来源
                />
            </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:USHalfHourHot
                        }}

                        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,
    },
});

  

.

posted @ 2017-08-31 20:10  每天都要进步一点点  阅读(531)  评论(0编辑  收藏  举报