zoukankan      html  css  js  c++  java
  • React-Native 之 项目实战(四)

    前言


    • 本文有配套视频,可以酌情观看。
    • 文中内容因各人理解不同,可能会有所偏差,欢迎朋友们联系我。
    • 文中所有内容仅供学习交流之用,不可用于商业用途,如因此引起的相关法律法规责任,与我无关。
    • 如文中内容对您造成不便,烦请联系 277511806@qq.com 处理,谢谢。
    • 转载麻烦注明出处,谢谢。

    数据持久化


    • 数据持久化是移动端的一个重要部分,刚发现 Realm 原来已经支持 React-Native 了,那么这边另起一篇专门介绍两种常用的存储方式 ———— React-Native 之 数据持久化

    • 这边没有发现 官方 有将 商品数据 做本地缓存的功能,为了让大家知道怎么做,我们就简单地来实验一下,具体逻辑在每个产品中都或多或少有些差异,这个朋友们就根据所学的灵活变通一下就可以了!

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

      	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;
      
    • 经过简单封装后,我们还需要引用一下框架,引用框架,我们就放到 main 文件内,这样我们就可以确保 全局变量 是在我们使用它之前就被调用过,避免找不到对象的错误(我们也同时将 HTTPBase 修改为全局,方便使用)。

      	import RealmStorage from '../storage/realmStorage';
      
    • 现在我们就来做下 本地持久化 实验,这边我们的逻辑就是,当网络出现问题的时候,每次都会进到 catch 中返回错误 code 告诉我们,出现了什么问题(既然进到这里了,是不是数据无论如何都不会加载成功?),那么我们就可以在这里 取出 本地数据,然后展示出来,那么数据的应该在哪里保存呢?这个我们只需要在每次 刷新 完成并且渲染完成后,保存一下数据就可以了。

      	// 加载最新数据网络请求
          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,
                      });
                  })
          }
      
    • 到这里,我们就完成了 数据本地持久化 并且成功将数据取出,这边数据持久化的实验就完成了。

    数据持久化.gif

    译注:

    • 有关 realm 的配置,可转到 React-Native 之 数据持久化 查看,这边不多赘述。

    • 当我们完全配置完 realm 后,会发现整个工程 多出将近500M+,不用担心,这些只不过是 realm 的依赖库,等我们后面 打包 后就不会有这么多东西了。

    • 我们已经使用了 git 进行对代码进行托管,那么,如果从仓库拉取最新数据时,是不是还是要重新配置 node_modules 文件夹,这个就很麻烦了,我们可以备份一下 node_modules 文件夹,将它 拷贝 进工程就可以使用了。

    .gitignore 语法


    • gitignore 文件内包含了需要忽略或保留的文件的一些配置,灵活使用可以减少我们的工作量,但是里面的内容是什么意思呢?这边也给大家说下:

      • /:表示目录
      • *:为通配多个字符
      • ?:通配单个字符
      • []:包含单个字符的匹配列表
      • !:表示不忽略匹配到的文件和目录
      • // 示例
      • // 忽略ios文件夹下的所有内容
    • 知道语法后,我们是不是就能看懂 工程中 gitignore 文件的内容了,举个栗子:

      	# Xcode					// 注释,说明这是 Xcode 配置
      	#
      	build/					// 忽略 build 文件夹下所有内容
      	*.pbxuser				// 忽略以 .pbxuser 为后缀的文件
      	!default.pbxuser		// 除 default.pbxuser 文件外
      	*.mode1v3				// 忽略以 .mode1v3	 为后缀的文件
      	!default.mode1v3		// 除 default.mode1v3	 文件外
      
      	# node.js				// 注释,说明这是 node 配置
      	#
      	node_modules/			// 忽略 node_modules 文件夹内所有内容
      	npm-debug.log			// 忽略 npm-debug.log	
      	yarn-error.log			// 忽略 yarn-error.log
      
    • 好了,就介绍到这里,希望可以帮到有需要的朋友,需要学习更多关于 git 的内容,可以到 git介绍与使用 查看学习。

    自定义详情cell


    • 到这边可能有人会想,前面不是已经自定义了 cell 了,为什么不直接在前面自定义的 cell 里面再添加一些操作,使所有的 cell 共用同一套组件?其实考虑到下面几点原因:

      • 可以看到 半小时热门的cell三大模块的cell 区别在于少了 优惠平台和数据提供平台 这一栏的2个控件,其他地方是一样的,如果我们做到一起那也是可以的,但是这样会造成一个组件里面担负过多业务逻辑,在 数据量少 是没关系,但是 数据量一多 那么需要渲染的成本就会增加,也就会严重影响到性能。

      • 如果我们分开使用,那么只是增加了组件,而且组件内部处理的业务逻辑变少了,这样也减少了我们后期的维护成本。

      • 从结构上来说,这样也更为的清晰,减少开发人员之间的沟通成本。

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

      	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,
      	        borderBottomWidth:0.5,
      	        borderBottomColor:'gray',
      	        marginLeft:15
      	
      	    },
      	
      	    imageStyle: {
      	        70,
      	        height:70,
      	    },
      	
      	    centerViewStyle: {
      	        height:70,
      	        justifyContent:'space-around',
      	    },
      	
      	    titleStyle: {
      	        width * 0.65,
      	    },
      	
      	    detailViewStyle: {
      	        flexDirection:'row',
      	        justifyContent:'space-between',
      	        alignItems:'center'
      	    },
      	    detailMallStyle: {
      	        fontSize:12,
      	        color:'green',
      	    },
      	    timeStyle: {
      	        fontSize:12,
      	        color:'gray',
      	    },
      	
      	    arrowStyle: {
      	        10,
      	        height:10,
      	        marginRight:30,
      	    }
      	});
      
      
    • OK,这边完成了,我们到首页中试一下是不是好使的。

    详情页.gif

    译注:

    • 这边需要注意的是时间的转化,方式有很多,这边就以最直接的方式来计算。

    • 还有需要注意的是在 JAVA 中,获取到的月份是和我们现在的月份少 1个月的,这是因为 JAVA 的月份是从 0 开始,Javascript 也是一样的。

    小时风云榜


    • 这个模块和首页、海淘请求数据方面是类似的,不同在于这里需要我们根据不同的时间段来进行相对应的请求,这边参考视频吧,直接上完整代码。

    • 还是 copy 首页或者海淘的代码,修改请求这部分代码:

    	export default class GDHourList extends Component {
    	
    	    // 构造
    	    constructor(props) {
    	        super(props);
    	        // 初始状态
    	        this.state = {
    	            dataSource: new ListView.DataSource({rowHasChanged:(r1, r2) => r1 !== r2}),
    	            loaded:false,
    	            prompt:'',
    	        };
    	
    	        this.nexthourhour = '';
    	        this.nexthourdate = '';
    	        this.lasthourhour = '';
    	        this.lasthourdate = '';
    	        this.loadData = this.loadData.bind(this);
    	    }
    	
    	    // 加载最新数据网络请求
    	    loadData(resolve, date, hour) {
    	        let params = {};
    	
    	        if (date) {
    	            params = {
    	                "date" : date,
    	                "hour" : hour
    	            }
    	        }
    	
    	        HTTPBase.get('http://guangdiu.com/api/getranklist.php', params)
    	            .then((responseData) => {
    	
    	                // 重新渲染
    	                this.setState({
    	                    dataSource: this.state.dataSource.cloneWithRows(responseData.data),
    	                    loaded:true,
    	                    prompt:responseData.displaydate + responseData.rankhour + '点档' + '(' + responseData.rankduring + ')'
    	                });
    	
    	                // 关闭刷新动画
    	                if (resolve !== undefined){
    	                    setTimeout(() => {
    	                        resolve();
    	                    }, 1000);
    	                }
    	
    	                // 暂时保留一些数据
    	                this.nexthourhour = responseData.nexthourhour;
    	                this.nexthourdate = responseData.nexthourdate;
    	                this.lasthourhour = responseData.lasthourhour;
    	                this.lasthourdate = responseData.lasthourdate;
    	            })
    	            .catch((error) => {
    	
    	            })
    	    }
    	
    	    // 跳转到设置
    	    pushToSettings() {
    	        this.props.navigator.push({
    	            component:Settings,
    	        })
    	    }
    	
    	    // 返回中间标题
    	    renderTitleItem() {
    	        return(
    	            <Image source={{uri:'navtitle_rank_106x20'}} style={styles.navbarTitleItemStyle} />
    	        );
    	    }
    	
    	    // 返回右边按钮
    	    renderRightItem() {
    	        return(
    	            <TouchableOpacity
    	                onPress={()=>{this.pushToSettings()}}
    	            >
    	                <Text style={styles.navbarRightItemStyle}>设置</Text>
    	            </TouchableOpacity>
    	        );
    	    }
    	
    	    // 根据网络状态决定是否渲染 listview
    	    renderListView() {
    	        if (this.state.loaded === false) {
    	            return(
    	                <NoDataView />
    	            );
    	        }else {
    	            return(
    	                <PullList
    	                    onPullRelease={(resolve) => this.loadData(resolve)}
    	                    dataSource={this.state.dataSource}
    	                    renderRow={this.renderRow.bind(this)}
    	                    showsHorizontalScrollIndicator={false}
    	                    style={styles.listViewStyle}
    	                    initialListSize={5}
    	                />
    	            );
    	        }
    	    }
    	
    	    // 跳转到详情页
    	    pushToDetail(value) {
    	        this.props.navigator.push({
    	            component:CommunalDetail,
    	            params: {
    	                url: 'https://guangdiu.com/api/showdetail.php' + '?' + 'id=' + value
    	            }
    	        })
    	    }
    	
    	    // 返回每一行cell的样式
    	    renderRow(rowData) {
    	        return(
    	            <TouchableOpacity
    	                onPress={() => this.pushToDetail(rowData.id)}
    	            >
    	                <CommunalCell
    	                    image={rowData.image}
    	                    title={rowData.title}
    	                    mall={rowData.mall}
    	                    pubTime={rowData.pubtime}
    	                    fromSite={rowData.fromsite}
    	                />
    	            </TouchableOpacity>
    	        );
    	    }
    	
    	    componentDidMount() {
    	        this.loadData();
    	    }
    	
    	    lastHour() {
    	        this.loadData(undefined, this.lasthourdate, this.lasthourhour);
    	    }
    	
    	    nextHour() {
    	        this.loadData(undefined, this.nexthourdate, this.nexthourhour);
    	    }
    	
    	    render() {
    	        return (
    	            <View style={styles.container}>
    	                {/* 导航栏样式 */}
    	                <CommunalNavBar
    	                    titleItem = {() => this.renderTitleItem()}
    	                    rightItem = {() => this.renderRightItem()}
    	                />
    	
    	                {/* 提醒栏 */}
    	                <View style={styles.promptViewStyle}>
    	                    <Text>{this.state.prompt}</Text>
    	                </View>
    	
    	                {/* 根据网络状态决定是否渲染 listview */}
    	                {this.renderListView()}
    	
    	                {/* 操作栏 */}
    	                <View style={styles.operationViewStyle}>
    	                    <TouchableOpacity
    	                        onPress={() => this.lastHour()}
    	                    >
    	                        <Text style={{marginRight:10, fontSize:17, color:'green'}}>{"< " + "上1小时"}</Text>
    	                    </TouchableOpacity>
    	
    	                    <TouchableOpacity
    	                        onPress={() => this.nextHour()}
    	                    >
    	                        <Text style={{marginLeft:10, fontSize:17, color:'green'}}>{"下1小时" + " >"}</Text>
    	                    </TouchableOpacity>
    	                </View>
    	            </View>
    	        );
    	    }
    	}
    	
    	const styles = StyleSheet.create({
    	    container: {
    	        flex: 1,
    	        alignItems: 'center',
    	        backgroundColor: 'white',
    	    },
    	
    	    navbarTitleItemStyle: {
    	        106,
    	        height:20,
    	        marginLeft:50
    	    },
    	    navbarRightItemStyle: {
    	        fontSize:17,
    	        color:'rgba(123,178,114,1.0)',
    	        marginRight:15,
    	    },
    	
    	    promptViewStyle: {
    	        width,
    	        height:44,
    	        alignItems:'center',
    	        justifyContent:'center',
    	        backgroundColor:'rgba(251,251,251,1.0)',
    	    },
    	
    	    operationViewStyle: {
    	        width,
    	        height:44,
    	        flexDirection:'row',
    	        justifyContent:'center',
    	        alignItems:'center',
    	    },
    	});
    

    小时风云榜.gif

    首页筛选功能


    • 从图中,我们可以看出筛选的下拉菜单类似 九宫格,这个我们在 React-Native 之 ListView使用 中有这样的案例,不清楚的可以再回去看一下,所以这边我们也使用 ListView 实现。

    • 在做之前,我们需要先配置一下,将压缩包内的 HomeSiftData文件HTSiftData 文件放到工程内。

    • 接着我们就要来完成这个筛选组件,代码如下:

    	export default class GDCommunalSiftMenu extends Component {
    	
    	    static defaultProps = {
    	        removeModal:{},
    	        loadSiftData:{}
    	    };
    	
    	    static propTypes = {
    	        data:PropTypes.array,
    	    };
    	
    	    // 构造
    	      constructor(props) {
    	        super(props);
    	        // 初始状态
    	        this.state = {
    	            dataSource: new ListView.DataSource({rowHasChanged:(r1, r2) => r1 !== r2})
    	        };
    	      }
    	
    	    // 退出
    	    popToHome(data) {
    	        this.props.removeModal(data);
    	    }
    	
    	    // 点击事件
    	    siftData(mall, cate) {
    	        this.props.loadSiftData(mall, cate);
    	        this.popToHome(false);
    	    }
    	
    	    // 处理数据
    	    loadData() {
    	        let data = [];
    	
    	        for (let i = 0; i<this.props.data.length; i++) {
    	            data.push(this.props.data[i]);
    	        }
    	
    	        // 重新渲染
    	        this.setState({
    	            dataSource: this.state.dataSource.cloneWithRows(data),
    	        })
    	    }
    	
    	    renderRow(rowData) {
    	        return(
    	            <View style={styles.itemViewStyle}>
    	                <TouchableOpacity
    	                    onPress={() => this.siftData(rowData.mall, rowData.cate)}
    	                >
    	                    <View style={styles.itemViewStyle}>
    	                        <Image source={{uri:rowData.image}} style={styles.itemImageStyle} />
    	                        <Text>{rowData.title}</Text>
    	                    </View>
    	                </TouchableOpacity>
    	            </View>
    	        )
    	    }
    	
    	    componentDidMount() {
    	        this.loadData();
    	    }
    	
    	    render() {
    	        return(
    	            <TouchableOpacity
    	                onPress={() => this.popToHome(false)}
    	                activeOpacity={1}
    	            >
    	                <View style={styles.container}>
    	                    {/* 菜单内容 */}
    	                    <ListView
    	                        dataSource={this.state.dataSource}
    	                        renderRow={this.renderRow.bind(this)}
    	                        contentContainerStyle={styles.contentViewStyle}
    	                        initialListSize={16}
    	                    />
    	                </View>
    	            </TouchableOpacity>
    	        )
    	    }
    	}
    	
    	const styles = StyleSheet.create({
    	    container: {
    	        width,
    	        height:height
    	    },
    	
    	    contentViewStyle: {
    	        flexDirection:'row',
    	        flexWrap:'wrap',
    	         width,
    	        top:Platform.OS === 'ios' ? 64 : 44,
    	    },
    	
    	    itemViewStyle: {
    	        width * 0.25,
    	        height:70,
    	        backgroundColor:'rgba(249,249,249,1.0)',
    	        justifyContent:'center',
    	        alignItems:'center'
    	    },
    	
    	    itemImageStyle: {
    	        40,
    	        height:40
    	    }
    	});
    
    • 我们点击某个平台,就要进行相应的请求,然后重新渲染 首页的ListView ,方式如下:
    	// 加载最新数据网络请求
        loadSiftData(mall, cate) {
    
            let params = {};
    
            if (mall === "" && cate === "") {   // 全部
                this.loadData(undefined);
                return;
            }
    
            if (mall === "") {  // cate 有值
                params = {
                    "cate" : cate
                };
            }else {
                params = {
                    "mall" : mall
                };
            }
    
    
            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,
                    });
    
                    // 存储数组中最后一个元素的id
                    let cnlastID = responseData.data[responseData.data.length - 1].id;
                    AsyncStorage.setItem('cnlastID', cnlastID.toString());
    
                })
                .catch((error) => {
    
                })
        }
    
    • 至此,首页的筛选功能也完成了,在 海淘模块 内也使用一下就可以了。

    筛选功能.gif

    搜索模块


    • 点击 首页或者海淘 右侧按钮,我们跳转到搜索模块,解析图奉上:

    • 根据解析图我们添加相应子组件。

      	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.changeText = '';
      	        this.loadData = this.loadData.bind(this);
      	        this.loadMore = this.loadMore.bind(this);
      	    }
      	
      	    // 加载最新数据网络请求
      	    loadData(resolve) {
      	
      	        if (!this.changeText) return;
      	
      	        let params = {
      	            "q" : this.changeText
      	        };
      	
      	        HTTPBase.get('http://guangdiu.com/api/getresult.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 searchLastID = responseData.data[responseData.data.length - 1].id;
      	                AsyncStorage.setItem('searchLastID', searchLastID.toString());
      	
      	            })
      	            .catch((error) => {
      	
      	            })
      	    }
      	
      	    // 加载更多数据的网络请求
      	    loadMoreData(value) {
      	
      	        let params = {
      	            "q" : this.changeText,
      	            "sinceid" : value
      	        };
      	
      	        HTTPBase.get('http://guangdiu.com/api/getresult.php', params)
      	            .then((responseData) => {
      	
      	                // 拼接数据
      	                this.data = this.data.concat(responseData.data);
      	
      	                this.setState({
      	                    dataSource: this.state.dataSource.cloneWithRows(this.data),
      	                    loaded:true,
      	                });
      	
      	                // 存储数组中最后一个元素的id
      	                let searchLastID = responseData.data[responseData.data.length - 1].id;
      	                AsyncStorage.setItem('searchLastID', searchLastID.toString());
      	            })
      	            .catch((error) => {
      	
      	            })
      	    }
      	
      	    // 加载更多数据操作
      	    loadMore() {
      	        // 读取id
      	        AsyncStorage.getItem('searchLastID')
      	            .then((value) => {
      	                // 数据加载操作
      	                this.loadMoreData(value);
      	            })
      	
      	    }
      	
      	    // 返回
      	    pop() {
      	        // 回收键盘
      	        dismissKeyboard();
      	
      	        this.props.navigator.pop();
      	    }
      	
      	    // 返回左边按钮
      	    renderLeftItem() {
      	        return(
      	            <TouchableOpacity
      	                onPress={() => {this.pop()}}
      	            >
      	                <View style={{flexDirection:'row', alignItems:'center'}}>
      	                    <Image source={{uri:'back'}} style={styles.navbarLeftItemStyle} />
      	                    <Text>返回</Text>
      	                </View>
      	
      	            </TouchableOpacity>
      	        );
      	    }
      	
      	    // 返回中间按钮
      	    renderTitleItem() {
      	        return(
      	            <Text style={styles.navbarTitleItemStyle}>搜索全网折扣</Text>
      	        );
      	    }
      	
      	    // ListView尾部
      	    renderFooter() {
      	        return (
      	            <View style={{height: 100}}>
      	                <ActivityIndicator />
      	            </View>
      	        );
      	    }
      	
      	    // 根据网络状态决定是否渲染 listview
      	    renderListView() {
      	        if (this.state.loaded === false) {
      	            return(
      	                <NoDataView />
      	            );
      	        }else {
      	            return(
      	                <PullList
      	                    onPullRelease={(resolve) => this.loadData(resolve)}
      	                    dataSource={this.state.dataSource}
      	                    renderRow={this.renderRow.bind(this)}
      	                    showsHorizontalScrollIndicator={false}
      	                    style={styles.listViewStyle}
      	                    initialListSize={5}
      	                    renderHeader={this.renderHeader}
      	                    onEndReached={this.loadMore}
      	                    onEndReachedThreshold={60}
      	                    renderFooter={this.renderFooter}
      	                />
      	            );
      	        }
      	    }
      	
      	    // 跳转到详情页
      	    pushToDetail(value) {
      	        this.props.navigator.push({
      	            component:CommunalDetail,
      	            params: {
      	                url: 'https://guangdiu.com/api/showdetail.php' + '?' + 'id=' + value
      	            }
      	        })
      	    }
      	
      	    // 返回每一行cell的样式
      	    renderRow(rowData) {
      	        return(
      	            <TouchableOpacity
      	                onPress={() => this.pushToDetail(rowData.id)}
      	            >
      	                <CommunalCell
      	                    image={rowData.image}
      	                    title={rowData.title}
      	                    mall={rowData.mall}
      	                    pubTime={rowData.pubtime}
      	                    fromSite={rowData.fromsite}
      	                />
      	            </TouchableOpacity>
      	        );
      	    }
      	
      	    render() {
      	        return (
      	            <View style={styles.container}>
      	                {/* 导航栏样式 */}
      	                <CommunalNavBar
      	                    leftItem = {() => this.renderLeftItem()}
      	                    titleItem = {() => this.renderTitleItem()}
      	                />
      	
      	                {/* 顶部工具栏 */}
      	                <View style={styles.toolsViewStyle} >
      	                    {/* 左边 */}
      	                    <View style={styles.inputViewStyle} >
      	                        <Image source={{uri:'search_icon_20x20'}} style={styles.searchImageStyle} />
      	                        <TextInput
      	                            style={styles.textInputStyle}
      	                            keyboardType="default"
      	                            placeholder="请输入搜索商品关键字"
      	                            placeholderTextColor='gray'
      	                            autoFocus={true}
      	                            clearButtonMode="while-editing"
      	                            onChangeText={(text) => {this.changeText = text}}
      	                            onEndEditing={() => this.loadData()}
      	                        />
      	                    </View>
      	
      	                    {/* 右边 */}
      	                    <View style={{marginRight:10}}>
      	                        <TouchableOpacity
      	                            onPress={() => this.pop()}
      	                        >
      	                            <Text style={{color:'green'}}>取消</Text>
      	                        </TouchableOpacity>
      	                    </View>
      	                </View>
      	
      	                {/* 根据网络状态决定是否渲染 listview */}
      	                {this.renderListView()}
      	            </View>
      	        );
      	    }
      	}
      	
      	const styles = StyleSheet.create({
      	    container: {
      	        flex: 1,
      	        alignItems: 'center',
      	        backgroundColor: 'white',
      	    },
      	
      	    navbarLeftItemStyle: {
      	        20,
      	        height:20,
      	        marginLeft:15,
      	    },
      	    navbarTitleItemStyle: {
      	        fontSize:17,
      	        color:'black',
      	        marginRight:50
      	    },
      	    navbarRightItemStyle: {
      	        20,
      	        height:20,
      	        marginRight:15,
      	    },
      	
      	    toolsViewStyle: {
      	        width,
      	        height:44,
      	        flexDirection:'row',
      	        alignItems:'center',
      	        justifyContent:'space-between',
      	    },
      	
      	    inputViewStyle: {
      	        height:35,
      	        flexDirection:'row',
      	        alignItems:'center',
      	        justifyContent:'center',
      	        backgroundColor:'rgba(239,239,241,1.0)',
      	        marginLeft:10,
      	        borderRadius:5
      	    },
      	    searchImageStyle: {
      	        15,
      	        height:15,
      	        marginLeft:8
      	    },
      	    textInputStyle: {
      	        width * 0.75,
      	        height:35,
      	        marginLeft:8
      	    },
      	
      	    listViewStyle: {
              width,
      	    },
      	});
      
      

    搜索页面.gif

    设置


    • 小时风云榜 模块,我们还有设置模块没有做,这边也快速来做一下

    • 从图中可以看出,这又是不一样的 cell样式 ,不过通过前面的经验,知道怎么来自定义了吧:

      	export default class GDSettingsCell extends Component {
      
      	    static propTypes = {
      	        leftTitle:PropTypes.string,
      	        isShowSwitch:PropTypes.bool,
      	    };
      	
      	    // 构造
      	      constructor(props) {
      	        super(props);
      	        // 初始状态
      	        this.state = {
      	            isOn:false,
      	        };
      	      }
      	
      	    // 返回需要的组件
      	    renderRightContent() {
      	        let component;
      	
      	        if (this.props.isShowSwitch) {  // 显示 Switch 按钮
      	
      	            component = <Switch value={this.state.isOn} onValueChange={() => {this.setState({isOn: !this.state.isOn})}} />
      	        }else {
      	            component = <Image source={{uri:'icon_cell_rightArrow'}} style={styles.arrowStyle} />
      	        }
      	
      	        return(
      	            component
      	        )
      	    }
      	
      	    render() {
      	        return(
      	            <View style={styles.container}>
      	                {/* 左边 */}
      	                <View>
      	                    <Text>{this.props.leftTitle}</Text>
      	                </View>
      	
      	                {/* 右边 */}
      	                <View style={styles.rightViewStyle}>
      	                    {this.renderRightContent()}
      	                </View>
      	            </View>
      	        )
      	    }
      	}
      	
      	const styles = StyleSheet.create({
      	    container: {
      	        flex:1,
      	        flexDirection:'row',
      	        height:Platform.OS === 'ios' ? 44 : 36,
      	        justifyContent:'space-between',
      	        alignItems:'center',
      	        borderBottomColor:'gray',
      	        borderBottomWidth:0.5,
      	        marginLeft:15,
      	    },
      	
      	    rightViewStyle:{
      	        marginRight:15,
      	    },
      	
      	    arrowStyle: {
      	        10,
      	        height:10,
      	    }
      	});
      
    • 自定义完成,来试下好不好用:

      	export default class GDSettings extends Component {
      	    // 返回
      	    pop() {
      	        this.props.navigator.pop();
      	    }
      	
      	    // 返回左边按钮
      	    renderLeftItem() {
      	        return(
      	            <TouchableOpacity
      	                onPress={() => {this.pop()}}
      	            >
      	                <View style={{flexDirection:'row', alignItems:'center'}}>
      	                    <Image source={{uri:'back'}} style={styles.navbarLeftItemStyle} />
      	                    <Text>返回</Text>
      	                </View>
      	
      	            </TouchableOpacity>
      	        );
      	    }
      	
      	    // 返回中间按钮
      	    renderTitleItem() {
      	        return(
      	            <Text style={styles.navbarTitleItemStyle}>设置</Text>
      	        );
      	    }
      	
      	    render() {
      	        return(
      	            <View style={styles.container}>
      	                {/* 导航栏样式 */}
      	                <CommunalNavBar
      	                    leftItem = {() => this.renderLeftItem()}
      	                    titleItem = {() => this.renderTitleItem()}
      	                />
      	
      	                {/* 内容 */}
      	                <ScrollView
      	                    style={styles.scollViewStyle}
      	                >
      	                    {/* 第一个cell */}
      	                    <SettingsCell
      	                        leftTitle="淘宝天猫快捷下单"
      	                        isShowSwitch={true}
      	                    />
      	
      	                    {/* 第二个cell */}
      	                    <SettingsCell
      	                        leftTitle="清理图片缓存"
      	                        isShowSwitch={false}
      	                    />
      	                </ScrollView>
      	            </View>
      	        )
      	    }
      	}
      	
      	const styles = StyleSheet.create({
      	    container: {
      	        flex:1
      	    },
      	
      	    navbarLeftItemStyle: {
      	        20,
      	        height:20,
      	        marginLeft:15,
      	    },
      	
      	    navbarTitleItemStyle: {
      	        fontSize:17,
      	        color:'black',
      	        marginRight:50
      	    },
      	
      	    scollViewStyle: {
      	        backgroundColor:'white',
      	    },
      	});
      

    设置.gif

  • 相关阅读:
    sql查询重复记录、删除重复记录方法大全
    查询字段所在的表/视图
    查询某张表被哪些存储过程或者视图用到的sql语句
    SQL中char、varchar、nvarchar的区别
    JS快速获取图片宽高的方法
    Git代码冲突常见解决方法
    HTML__图片轮播ion-slide-box
    oracle列出两个日期间所有日期
    myeclipse 8.0 注册码
    网页中图片旋转的几种实现方式
  • 原文地址:https://www.cnblogs.com/miaomiaoshen/p/6680464.html
Copyright © 2011-2022 走看看