React-Native 之 项目实战(五)
前言
- 本文 有配套视频,可以酌情观看。
- 文中内容因各人理解不同,可能会有所偏差,欢迎朋友们联系我讨论。
- 文中所有内容仅供学习交流之用,不可用于商业用途,如因此引起的相关法律法规责任,与我无关,如文中内容对您造成不便,烦请联系 277511806@qq.com 处理,谢谢。
- 转载麻烦注明出处,谢谢。
本篇资源:链接: https://pan.baidu.com/s/1qXH2qx2 密码: b5sj
源码托管到 github 上,需要源码的 点我下载,喜欢的话记得 Star,谢谢!
本章许多内容本来是要放到后面讲的,考虑到有朋友可能不需要了解
redux相关内容,所以把能想到的一些常见的东西先讲下。
小时风云榜按钮处理
- 在服务器返回给我们的 - json数据中,提供了- hasnexthour字段,当这个字段返回为- 1的时候,表示后面还有内容,按钮可以点击,否则不能点击,按照这个思路,我们就来完成这个功能。
- 在 - state中新增- isNextTouch状态- isNextTouch:false // 下一小时按钮状态
 
- 在每次请求成功后都更新下状态: - let isNextTouch = true; if (responseData.hasnexthour == 1) { // hasnexthour不为0时 下一小时 按钮可点击
 isNextTouch = false;
 } // 重新渲染
 this.setState({
 dataSource: this.state.dataSource.cloneWithRows(responseData.data),
 loaded:true,
 prompt:responseData.displaydate + responseData.rankhour + '点档' + '(' + responseData.rankduring + ')',
 isNextTouch:isNextTouch, // 更新按钮状态
 });
 
- 接着我们就可以根据状态进行相应更改: - {/* 下一小时按钮 */}
 <TouchableOpacity
 onPress={() => this.nextHour()}
 disabled={this.state.isNextTouch}
 >
 <Text style={{marginLeft:10, fontSize:17, color:this.state.isNextTouch == false ? 'green' : 'gray'}}>{"下1小时" + " >"}</Text>
 </TouchableOpacity>
 

ref 和 setNativeProp 的使用
- 使用 - ref可以获取到相应的组件,更加灵活地在需要的地方使用,配合- setNativeProps可以做到不直接调用- render直接渲染组件,在某些频繁更新的组件上使用,可以- 大大提高性能,不过- 千万不要为了使用- setNativeProps而使用,某些情况下可能会适得其反。
- 使用方法如下: 
 test() {
 this.refs.testText.setNativeProps({
 style: {
 backgroundColor:'green'
 }
 })
 } <Text ref="testText">快,说我帅</Text>
 
监听 TabBarItem 点击与传值实现 点击 Item 进行刷新功能
- 原版 - APP中当我们点击- 首页和海淘2个- Item时,会马上获取最新数据个数然后进行更新,这边来实现一下这个功能。
- 通过通知的方式监听Item点击做相应的操作,所以我们在需要接收通知的页面注册一下通知,在需要的地方发送通知即可: - 在 home界面注册通知
 - // 组件加载完成
 componentDidMount() {
 // 注册通知
 this.subscription = DeviceEventEmitter.addListener('clickHomeItem', () => this.clickTabBarItem());
 }
 - 在页面销毁之前记得注销下:
 - componentWillUnmount() {
 // 注销通知
 this.subscription.remove();
 }
 - clickTabBarItem方法逻辑:
 - // 点击了Item
 clickTabBarItem() {
 // 加载最新数据
 this.loadData();
 }
 
- 在 
- 回到 - Main页面,我们修改下点击- Item响应的事件:- 修改 Item点击事件:
 - onPress={() => this.clickItem(selectedTab, subscription)}>
 - clickItem方法逻辑:
 - // 点击了Item
 clickItem(selectedTab, subscription) { if (subscription !== "" && this.state.selectedTab == selectedTab) {
 // 发送通知
 DeviceEventEmitter.emit(subscription);
 } // 渲染页面
 this.setState({ selectedTab: selectedTab })
 }
 - 所以传值也需要新增 - subscription参数,不需要订阅的按钮就可以传- ""即可。
- 海淘也是类似操作,这边就不赘述,自己试着实现一下。 
 
- 修改 
每次点击 Item 获取到最新数据后我们需要及时更新 Item 角标
- 实现思路很简单,我们使用逆传的方式,每次获取到最新数据的时候,同时需要调用一下 在 - main中- 获取最新数据个数的请求方法即可。- 首先我们在 - home定义一个属性供外界使用:- static defaultProps = {
 loadDataNumber:{}, // 回调
 };
 
- 接着,当我们请求到最新数据的同时,我们调用一下这个属性,就可以了: - // 获取最新数据个数
 this.loadDataNumber(); // loadDataNumber 中的逻辑
 loadDataNumber() {
 // 调用 this.props.loadDataNumber 中保存的代码块
 this.props.loadDataNumber();
 }
 
- 为了方便调用,我们将 - 获取最新数据个数的逻辑抽出来放到单独的方法内,这边顺便再介绍- AsyncStorage怎么同时获取多个- key值的方法:- // 获取最新数据个数网络请求
 loadDataNumber() {
 // 取出id
 AsyncStorage.multiGet(['cnfirstID', 'usfirstID'], (error, stores) => {
 // 拼接参数
 let params = {
 "cnmaxid" : stores[0][1],
 "usmaxid" : stores[1][1],
 }; // 请求数据
 HTTPBase.get('http://guangdiu.com/api/getnewitemcount.php', params)
 .then((responseData) => {
 this.setState({
 cnbadgeText:responseData.cn,
 usbadgeText:responseData.us
 })
 })
 .catch((error) => { })
 });
 }
 
- 很好,接着我们转到 main 中,修改下 - renderTabBarItem方法中的内容,实现一下 `` 属性的方法:- renderScene={(route, navigator) => {
 let Component = route.component;
 return <Component {...route.params}
 navigator={navigator}
 loadDataNumber={() => this.loadDataNumber()} />
 }}
 
- 到这里就完成了,海淘页面也是类似操作,自己试着实现一下。 
 
一键置顶功能
- 一键置顶功能也是市面上 - APP上可以说必备功能了,这边- 原版APP也有这个功能,所以我们跟着来实现一下。
- 这个功能实现更加简单,只要我们调用 - ScrollView的- scrollTo方法,将- y设置为 0 即可;因为- ListView是在- ScrollView上进行的二次开发,所以它可以使用- ScrollView的所有方法:- // 点击了Item
 clickTabBarItem() {
 let PullList = this.refs.pullList;
 // 一键置顶
 PullList.scrollTo({y:0});
 }
 
- 这样我们的一键置顶功能就完成了,在需要的页面进行同样操作就可以实现相同功能。 
TabBarItem 逻辑完善
- 那么为了更好的用户体验,我们这边还需要来处理一下点击 - TabBarItem的一下细节,那就是当用户点击- Item时,可能只是单纯的想进行页面的- 切换或者置顶操作,而不想进行- 刷新,那么我们就需要来判断一下什么时候需要刷新,什么时候需要置顶。
- 那么我们可以通过判断 - ListView中的- Scroll的偏移量来判断是否需要进行置顶操作,当偏移量大于 1 的时候我们就进行置顶操作,否则的话我们就进行刷新操作。
- 那么问题又来了,当我们执行刷新操作的时候,应该模拟用户下拉显示 - 滚动小菊花来告诉用户我们在进行刷新操作,可是- pullList并没有提供我们这个方法怎么办?那我们就需要分析- 第三方框架的内容来找方法解决这个问题(具体方法,可以观看我为各位录制的视频),这边就不多讲了,直接上最终代码:- // 点击了Item
 clickTabBarItem() { let PullList = this.refs.pullList; if (PullList.scroll.scrollProperties.offset > 0) { // 不在顶部
 // 一键置顶
 PullList.scrollTo({y:0});
 }else { // 在顶部 // 执行下拉刷新动画
 PullList.state.pullPan = new Animated.ValueXY({x: 0, y: this.topIndicatorHeight * -1}); // 加载最新数据
 this.loadData(); // 关闭动画
 setTimeout(() => {
 PullList.resetDefaultXYHandler();
 },1000);
 }
 }
 

关闭筛选菜单滑动手势
- 那这边我们的筛选菜单还有个问题,就是可以响应我们的手势进行滚动,这样肯定是不对的,那么我们需要关闭这个手势的监听,使这个菜单不能滚动,具体操作如下: - {/* 菜单内容 */}
 <ListView
 scrollEnabled={false} // 关闭滑动功能
 dataSource={this.state.dataSource} // 设置数据源
 renderRow={this.renderRow.bind(this)} // 根据数据初始化 Cell
 contentContainerStyle={styles.contentViewStyle} // 样式
 initialListSize={16} // 一次性渲染几行数据
 />
 

Navigator 掉帧卡顿问题处理
- 到现在肯定有很多朋友发现 - Navigator跳转动画并不是那么流畅,会出现掉帧卡顿的现象,并不像- NavigatorIOS那么丝丝顺滑;造成这个的原因是因为- NavigatorIOS是在 UI线程 执行的 动画操作,而- Navigator是在 JS线程执行的动画,那这样就会 阻塞住 JS线程,那么怎么去解决这个问题?这边提供 2 种方案:- 第一种:使用 navigation 框架,这个是目前替代 navigator 最好的方案之一,很强大,很流畅,但是需要再去学习一下使用。 
- 第二种:如果你懒得学习上面的框架,那么这边再给各位提供另一种方法 —— 使用官方提供的 API:InteractionManager(可以将一些耗时较长的工作安排到所有互动或动画完成之后再进行。这样可以保证JavaScript动画的流畅运行),这边我们就使用这种方案来进行一下优化: - InteractionManager.runAfterInteractions(() => {
 this.props.navigator.push({
 component: Search,
 });
 });
 
 
- 是的,就这一步操作即可,在其他需要用到 跳转功能的地方 使用一下这个API即可。 

怎样调用框架中没有提供我们使用的接口
- 这个篇幅较大,感兴趣的朋友还是参考录制的视频吧。
removeClippedSubviews
- 用于提升大列表的滚动性能。需要给行容器添加样式overflow:'hidden'。(Android已默认添加此样式)此属性默认开启 
- 这个属性是因为在早期 - ListView在数据到达一定程度的时候就会越来越卡,最终导致 APP 崩溃退出,使用这个属性后 APP 崩溃确实在一定程度上得到缓解,但是卡顿问题还是依旧存在。那等到后面我们会介绍- FlatList,它将是未来- ListView替代品,主要解决它性能差的,占用内容持续增加的问题,目前还没发布稳定版本,但是经过一段时间测试,我觉得已经可以向大家推荐了,所以在后面的章节中会为各位介绍的。
- 废了这么多话,这边我们就先来使用一下 - removeClippedSubviews,很简单,使用它只需要在我们封装的 cell 中的- container样式中添加- overflow:'hidden'即可。- container: {
 flexDirection:'row',
 alignItems:'center',
 justifyContent:'space-between',
 backgroundColor:'white',
 height:120,
 width:width,
 borderBottomWidth:0.5,
 borderBottomColor:'gray',
 marginLeft:15,
 overflow:'hidden',
 },
 
modal放置的顺序
- 这边我们试了下安卓,发现当我们显示 modal 然后又关闭 modal 的时候,就会出现 ListView 列表消失的问题,那么其实是因为我们 modal 放置的顺序问题,modal 应当放置到所有主视图之后创建,避免它影响其他视图显示,这边就以 - home页面为例,其他视图自己实现哈:- render() {
 return (
 <View style={styles.container}>
 {/* 导航栏样式 */}
 <CommunalNavBar
 leftItem = {() => this.renderLeftItem()}
 titleItem = {() => this.renderTitleItem()}
 rightItem = {() => this.renderRightItem()}
 /> {/* 根据网络状态决定是否渲染 listview */}
 {this.renderListView()} {/* 初始化近半小时热门 */}
 <Modal pointerEvents={'box-none'}
 animationType='slide'
 transparent={false}
 visible={this.state.isHalfHourHotModal}
 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> {/* 初始化筛选菜单 */}
 <Modal pointerEvents={'box-none'}
 animationType='none'
 transparent={true}
 visible={this.state.isSiftModal}
 onRequestClose={() => this.onRequestClose()}
 >
 <CommunalSiftMenu
 removeModal={(data) => this.closeModal(data)}
 data={HomeSiftData}
 loadSiftData={(mall, cate) => this.loadSiftData(mall, cate)} />
 </Modal>
 </View>
 );
 }
 
- 原因我们之后会带大家来自己 开发一个类似 modal 的组件,到时候再跟大家详解。 

Android 加载git图\动图
- 细心的朋友应该发现了一个问题,同样一张 git 图片,在 iOS 上可以正常加载,在 Android 上图片竟然不能动,可能会想算了吧,能显示图片就行了?转头发现,产品经理正 “悠闲” 磨刀呢。。。那其实解决这个问题很简单,我们只需要使用一下 facebokk 的一个强大的图片加载库就能解决这个问题了。 
- 首先,我们打开 - build.gradle,在- dependencies中添加下面一行代码- compile "com.facebook.fresco:animated-gif:0.13.0"
 
- 重新 run 一下,编译器会自动帮我们添加这个库并配置完毕,那么 Android 上也可以愉快地显示 gif图片 了。 
- 什么?找不到这个文件?那可不行,看一下给各位录制的视频吧。 

导航栏返回按钮
- 我们导航栏的返回按钮很挫对吧,这边统一简单先改一下: - // 返回左边按钮
 renderLeftItem() {
 return(
 <TouchableOpacity
 onPress={() => {this.pop()}}
 >
 <View style={{flexDirection:'row', alignItems:'center'}}>
 <Image source={{uri:'back'}} style={styles.navbarLeftItemStyle} />
 <Text>返回</Text>
 </View> </TouchableOpacity>
 );
 }
 

去除 Android 中输入框的下划线
- 那么 Android 中的 - TextInput的下划线是不是丑爆了?这边我们也来处理下它,直接使用- underlineColorAndroid这个属性,让他为透明即可。- underlineColorAndroid={'transparent'}
 

navigationBar
- 这边先来介绍一下 - navigationBa的使用,使用它可以让我们只在一个地方管理- navigator导航栏的样式,就不用像现在这样在每个页面都手动添加导航栏。
- 这边先举个例子让大家知道怎么用,考虑到传值不方便的原因,到讲完 - redux之后,再一起讲这部分内容,所以大家只需要了解一下怎么使用就可以了。
- 首先,我们来看下 - navigationBar文件内的内容:- let NavigationBarRouteMapper = {
 LeftButton(route, navigator, index, navState) {
 if (index > 0) {
 return (
 <TouchableOpacity
 onPress={() => navigator.pop()}
 >
 <Text>返回</Text>
 </TouchableOpacity>
 )
 }
 }, RightButton(route, navigator, index, navState) { }, Title(route, navigator, index, navState) {
 return(
 <Text>{route.name}</Text>
 )
 },
 }; export default (
 <Navigator.NavigationBar
 style={{backgroundColor:'green'}}
 routeMapper={NavigationBarRouteMapper}
 />
 )
 
- 接着,我们到 - main文件中使用一下这个- navigationBar:- navigationBar={NavigationBar}
 

react-native 开发中你可能需要的一些小玩意
- 拨打电话(真机测试,模拟器没有打电话功能): - import { Linking } from ‘react-native’; function callPhone() {
 return Linking.openURL('tel:10086');
 }
 
- 获取视图组件的 x,y,宽,高,偏移量的值,可以使用 measure 方法: - this.refs.mainView.measure((x, y, width, height, px,py)) => {
 console.log(width);
 }
- 开发中建议先从 iOS 端做起,安卓端适配;当然如果公司不是只有你一个人负责 react-native 项目,大可不必理会这条。 
- 开发中有些功能在 模拟器 上是无法测试的,这时候需要配合真机进行调试,下面整理出一些常见的问题: - 当 Android 提示找不到服务器时: - 确定电脑与我们手机连接同一个 WiFi 网络环境下。 
- 我们需要打开 开发中菜单(摇下手机) —— —— —— 输入电脑IP地址(IP地址怎么找?自己搜索吧)—— 退出菜单 —— 
 
- 当 iOS 提示找不到服务器时: - 打开 Xcode —— AppDelegate.m 文件 —— 更改 jsCodeLocation 中的 localhost 为电脑的IP地址 —— 重新运行一遍。
 
 
优化工具介绍与使用
- 本来要讲的,但是发现现在的项目还没出现太明显性能问题,不好测试,就放到最后面讲吧。
第一版完结
- 到这里第一个版本就完结了,接下来就要开始我们的第二版本的开发了,那么第二个版本之前大概会用一篇的内容来主要讲下 - react怎么结合- redux进行开发,并做个小 Demo,让大家先熟悉一下- redux使用,然后就是我们当前的项目 转为- redux开发了。
- 这边想知道大家更想知道或者对于 - redux哪里比较不理解的,好跟着改进一下,尽量使文章和视频更易懂。
React-Native 之 项目实战(五)的更多相关文章
- React Native 之 项目实战(一)
		前言 本文有配套视频,可以酌情观看. 文中内容因各人理解不同,可能会有所偏差,欢迎朋友们联系我. 文中所有内容仅供学习交流之用,不可用于商业用途,如因此引起的相关法律法规责任,与我无关. 如文中内容对 ... 
- React Native商城项目实战04 - 封装TabNavigator.Item的创建
		1.Main.js /** * 主页面 */ import React, { Component } from 'react'; import { StyleSheet, Text, View, Im ... 
- React Native商城项目实战02 - 主要框架部分(tabBar)
		1.安装插件,cd到项目根目录下执行: $ npm i react-native-tab-navigator --save 2.主框架文件Main.js /** * 主页面 */ import Rea ... 
- React Native商城项目实战01 - 初始化设置
		1.创建项目 $ react-native init BuyDemo 2.导入图片资源 安卓:把文件夹放到/android/app/src/main/res/目录下,如图: iOS: Xcode打开工 ... 
- React Native商城项目实战07 - 设置“More”界面导航条
		1.More/More.js /** * 更多 */ import React, { Component } from 'react'; import { AppRegistry, StyleShee ... 
- React Native商城项目实战05 - 设置首页的导航条
		1.Home.js /** * 首页 */ import React, { Component } from 'react'; import { AppRegistry, StyleSheet, Te ... 
- React Native商城项目实战06 - 设置安卓中的启动页
		1.Main 目录下新建LaunchImage.js: /** * 启动页 */ import React, { Component } from 'react'; import { AppRegis ... 
- React Native商城项目实战03 - 包装Navigator
		1.在Home目录下新建首页详细页HomeDetail.js /** * 首页详情页 */ import React, { Component } from 'react'; import { App ... 
- React Native商城项目实战16 - 购物中心详细页
		逻辑分析: 首页(Home)加载的购物中心组件(ShopCenter),传递url数据: ShopCenter里根据url加载购物中心详细页组件(ShopCenterDetail), ShopCent ... 
- React Native商城项目实战15 - 首页购物中心
		1.公共的标题栏组件TitleCommonCell.js /** * 首页购物中心 */ import React, { Component } from 'react'; import { AppR ... 
随机推荐
- PDO预处理语句规避SQL注入攻击
			所谓SQL注入式攻击,就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令.在某些表单中,用户输入的内容直接用来构造(或者影响)动态SQL命令,或作为存 ... 
- 写lua时需要注意的地方
			条件语句判断时,只有false和nil会导致判断为假,其他的任何值都为真. Lua 的字符串与编码无关: 它不关心字符串中具体内容. 标准 Lua 使用 64 位整数和双精度(64 位)浮点数, 但你 ... 
- J2ee技术难点
			J2ee技术难点 session/cookie区别联系 jsp/servlet区别联系 filter执行流程 openSessionInView原理 clone与servilizable区别联系 eq ... 
- Visual Studio 20周年软件趋势随想
			从2002年开始,.net让开发人员能快速构建和部署应用程序,便捷的开发windows和web服务器应用,同时著名的hacker Miguel de Icaza ,Miguel 为了GNOME项目启动 ... 
- Compare Version Numbers leetcode
			Compare two version numbers version1 and version2.If version1 > version2 return 1, if version1 &l ... 
- 2435: [Noi2011]道路修建
			2435: [Noi2011]道路修建 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2188 Solved: 639[Submit][Status ... 
- 1202: [HNOI2005]狡猾的商人
			1202: [HNOI2005]狡猾的商人 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1554 Solved: 745[Submit][Stat ... 
- Android: Toolbar、AppBarLayout
			ToolBar是google退出的一个应用程序动作条 包括: 设置导航栏图标 设置应用程序Logo 设置标题 设置子标题 添加各种自定义控件 添加动作条菜单 API:https://developer ... 
- SPM HW1 A project
			项目分析 --民航航班异常轨迹可视分析 最近完成的一个项目是一个可视化大作业--民航航班异常轨迹可视分析.要求利用已给的8G飞机的飞行记录数据,将飞机的飞行轨迹在浏览器中进行飞行轨迹高维可视化以及对异 ... 
- SEO-搜索引擎高级搜索指令
			搜索引擎高级搜索指令 1.双引号 把搜索词放在双引号中,代表完全匹配搜索,也就是说搜索结果返回的页面包含双引号中出现的所有的词,连顺序也必须完全匹配.bd和Google 都支持这个指令.例如搜索: & ... 
