经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » React » 查看文章
【React Native】React Native项目设计与知识点分享
来源:cnblogs  作者:零零圈圈  时间:2019/6/6 8:53:35  对本文有异议

  闲暇之余,写了一个React Native的demo,可以作为大家的入门学习参考。

  GitHub:https://github.com/xujianfu/React-Native-CarProject.git

  项目截图如下:

 

 一、项目界面设计

  1、React Navigation的应用

   React Navigation 源于 React Native 社区对一个可扩展且易于使用的导航解决方案的需求,它完全使用 JavaScript 编写(因此你可以阅读并理解所有源码)。支持iOS/Android.

   1、如何在项目进行使用?

  1. yarn add react-navigation
  2. # or with npm
  3. # npm install --save react-navigation

  然后,安装 react-native-gesture-handler。 如果你正在使用 Expo managed workflow,那么你什么都不需要做, SDK 中已经包含了这些. 否则:  

  1. yarn add react-native-gesture-handler
  2. # or with npm
  3. # npm install --save react-native-gesture-handler

  最后进行Link 所有的原生依赖

  1. react-native link react-native-gesture-handler

  2、路由配置

  为某个模块创建StackNavigator导航

  1. const HomeStack = createStackNavigator(
  2. {
  3. Home:{
  4. screen:HomeScreen,
  5. navigationOptions:()=>({
  6. headerBackTitle: null,
  7. })
  8. },
  9. //添加多个路由
  10. CarLoans:CarLoansScreen,
  11. CheckRules:CheckRulesScreen,
  12. },
  13. )
  14. ......

  将多个模块添加到TabNavigator上

  1. const TabNavigator = createBottomTabNavigator(
  2. {
  3. Home:{
  4. screen:HomeStack,
  5. navigationOptions:({navigation}) => ({
  6. tabBarLabel:'首页',
  7. tabBarIcon:({focused}) => (
  8. <Image source={{uri:focused ? 'ic_tab_home_h':'ic_tab_home_n.png'}} style={styles.iconStyle}/>
  9. ),
  10. }),
  11. },
  12. Mall:{
  13. screen:MallStack,
  14. navigationOptions:({navigation}) => ({
  15. tabBarLabel:'商城',
  16. tabBarIcon:({focused}) => (
  17. <Image source={{uri:focused ? 'ic_tab_mall_h':'ic_tab_mall_n.png'}} style={styles.iconStyle}/>
  18. )
  19. }),
  20. },
  21. Publish:{
  22. screen:PublishStack,
  23. navigationOptions:({navigation}) => ({
  24. tabBarLabel:'发布',
  25. tabBarIcon:({focused}) => (
  26. <Image source={{uri:focused ? 'ic_tab_release_h':'ic_tab_release_n.png'}} style={styles.iconStyle}/>
  27. )
  28. }),
  29. },
  30. Discover:{
  31. screen:DiscoverStack,
  32. navigationOptions:({navigation}) => ({
  33. tabBarLabel:'发现',
  34. tabBarIcon:({focused}) => (
  35. <Image source={{uri:focused ? 'ic_tab_find_h':'ic_tab_find_n.png'}} style={styles.iconStyle}/>
  36. )
  37. }),
  38. },
  39. Mine:{
  40. screen:MineStack,
  41. navigationOptions:({navigation}) => ({
  42. tabBarLabel:'我的',
  43. tabBarIcon:({focused}) => (
  44. <Image source={{uri:focused ? 'ic_tab_my_h':'ic_tab_my_n.png'}} style={styles.iconStyle}/>
  45. )
  46. }),
  47. },
  48. },
  49. {
  50. defaultNavigationOptions: ({ navigation }) => {
  51. let tabBarVisible = true;
  52. if (navigation.state.index > 0) {
  53. tabBarVisible = false;
  54. }
  55. return {
  56. tabBarVisible,
  57. };
  58. },
  59. tabBarPosition:'bottom',
  60. tabBarOptions: {
  61. activeTintColor: 'blue', //选中tabbar的文字颜色
  62. inactiveTintColor: 'gray',
  63. showIcon:true,
  64. },
  65. }
  66. );
  67. export default createAppContainer(TabNavigator);

  2、选择相册照片或视频,或进行拍照

  (1)引入react-native-image-picker

  1. yarn add react-native-image-picker
  2. react-native link react-native-image-picker

  (2)在项目中使用react-native-image-picker

  1. import ImagePicker from 'react-native-image-picker';
  2. //选择图片
  3. selectPhotoTapped() {
  4. const options = {
  5. // 弹窗标题
  6. title: '选择图片',
  7. cancelButtonTitle: '取消',
  8. takePhotoButtonTitle: '拍照',
  9. chooseFromLibraryButtonTitle: '选择照片',
  10. // 自定义按钮
  11. customButtons: [
  12. {name: 'fb', title: 'Choose Photo from Facebook'},
  13. ],
  14. // 相机类型'front' 或者 'back'
  15. cameraType: 'back',
  16. // 图片或视频:'photo','video'
  17. mediaType: 'photo',
  18. // 视频质量
  19. videoQuality: 'high',
  20. //最大视频录制时间
  21. durationLimit: 10,
  22. //最长宽
  23. maxWidth: 300,
  24. //最长高,
  25. maxHeight: 300,
  26. //图片质量
  27. quality: 0.8,
  28. angle: 0,
  29. //是否可以编辑
  30. allowsEditing: false,
  31. //如果为真,则禁用data生成的base64字段
  32. noData: false,
  33. // 如果提供此密钥,该图像将被保存在Documents iOS 应用程序的目录中,或者保存在PicturesAndroid上的应用程序目录(而不是临时目录)
  34. storageOptions: {
  35. skipBackup: true
  36. }
  37. };
  38. ImagePicker.showImagePicker(options, (response) => {
  39. console.log('Response = ', response);
  40. if (response.didCancel) {
  41. console.log('User cancelled photo picker');
  42. }
  43. else if (response.error) {
  44. console.log('ImagePicker Error: ', response.error);
  45. }
  46. else if (response.customButton) {
  47. console.log('User tapped custom button: ', response.customButton);
  48. }
  49. else {
  50. let source = { uri: response.uri };
  51. // You can also display the image using data:
  52. // let source = { uri: 'data:image/jpeg;base64,' + response.data };
  53.  
  54. this.setState({
  55. avatarSource: source
  56. });
  57. }
  58. });
  59. }
  60. //选择视频
  61. selectVideoTapped() {
  62. const options = {
  63. title: '选择视频',
  64. cancelButtonTitle: '取消',
  65. takePhotoButtonTitle: '录制视频',
  66. chooseFromLibraryButtonTitle: '选择视频',
  67. mediaType: 'video',
  68. videoQuality: 'medium'
  69. };
  70. ImagePicker.showImagePicker(options, (response) => {
  71. console.log('Response = ', response);
  72. if (response.didCancel) {
  73. console.log('User cancelled video picker');
  74. }
  75. else if (response.error) {
  76. console.log('ImagePicker Error: ', response.error);
  77. }
  78. else if (response.customButton) {
  79. console.log('User tapped custom button: ', response.customButton);
  80. }
  81. else {
  82. this.setState({
  83. videoSource: response.uri
  84. });
  85. }
  86. });
  87. }

 3、创建切换选项卡

  导入react-native-scrollable-tab-view

  1. npm install react-native-scrollable-tab-view --save

  项目中引入

  1. //引用插件
  2. import ScrollableTabView, { ScrollableTabBar, DefaultTabBar } from 'react-native-scrollable-tab-view';
  3. <ScrollableTabView
  4. initialPage={0}
  5. renderTabBar={() => <ScrollableTabBar style={{borderBottomWidth: 0,height: 44}}/>}
  6. tabBarTextStyle={{fontSize:16}}
  7. tabBarActiveTextColor={'#fdd000'}
  8. tabBarInactiveTextColor={'#999999'}
  9. tabBarUnderlineStyle={{backgroundColor:'#fdd000'}}
  10. >
  11. {
  12. label.map((item,index) =>{
  13. if (index === 0) {
  14. return <AllBusinessScreen tabLabel={item} key={index}/>
  15. } else {
  16. return <NearByBusinessScreen tabLabel={item} key={index}/>
  17. }
  18. })
  19. }
  20. </ScrollableTabView>

  4、使用Modal组件

  Modal组件可以用来覆盖包含React Native根视图的原生视图(如UIViewController,Activity)。在嵌入React Native的混合应用中可以使用Modal。Modal可以使你应用中RN编写的那部分内容覆盖在原生视图上显示。  

  1. <Modal
  2. animationType={"slide"}
  3. transparent={true}
  4. visible={this.state.modalVisible}
  5. onRequestClose={()=>{alert('modal has been closed')}}
  6. >
  7. <View style={styles.modalStyle}>
  8. <View style={styles.coverStyle}>
  9. {this.renderItem()}
  10. </View>
  11. </View>
  12.  
  13.  
  14. </Modal>
  15. ......
  16. renderItem(){
  17. let itemTitleArr = ['京','沪','浙','苏','粤','鲁','晋','冀',
  18. '豫','川','渝','辽','吉','黑','皖','鄂',
  19. '湘','赣','闽','陕','甘','宁','蒙','津',
  20. '贵','云','桂','琼','青','新','藏'];;
  21. var itemArr = [];
  22. for (var i = 0; i < itemTitleArr.length; i++) {
  23. itemArr.push(
  24. <TouchableHighlight onPress={this.callBack.bind(this,itemTitleArr[i])} key={i}>
  25. <View style={styles.chooseItemStyle} >
  26. <Text style={styles.chooseTitleStyle}>{itemTitleArr[i]}</Text>
  27. </View>
  28. </TouchableHighlight>
  29. )
  30. }
  31. return itemArr;
  32. }

  5、下拉列表实现

  1. import React, {Component} from 'react';
  2. import {View, Text, Image, TouchableOpacity, ScrollView, Animated, Easing, StyleSheet} from 'react-native';
  3. import PropTypes from 'prop-types';
  4. class DropdownMenu extends Component {
  5. constructor(props, context) {
  6. super(props, context);
  7. var selectIndex = new Array(this.props.data.length);
  8. for (var i = 0; i < selectIndex.length; i++) {
  9. selectIndex[i] = 0;
  10. }
  11. this.state = {
  12. activityIndex: -1,
  13. selectIndex: selectIndex,
  14. rotationAnims: props.data.map(() => new Animated.Value(0))
  15. };
  16. this.defaultConfig = {
  17. bgColor: '#f5f5f5',
  18. tintColor: '#fdd000',
  19. activityTintColor: "red",
  20. arrowImg: 'ic_nav_down',
  21. checkImage: 'ic_nav_down'
  22. };
  23. }
  24. renderChcek(index, title) {
  25. var activityIndex = this.state.activityIndex;
  26. if (this.state.selectIndex[activityIndex] === index) {
  27. var checkImage = this.props.checkImage ? this.props.checkImage : this.defaultConfig.checkImage;
  28. return (
  29. <View style={{flex: 1, justifyContent: 'space-between', alignItems: "center", paddingHorizontal: 15, flexDirection: 'row'}} >
  30. <Text
  31. style={[
  32. styles.item_text_style,
  33. this.props.optionTextStyle,
  34. {color: this.props.activityTintColor ? this.props.activityTintColor : this.defaultConfig.activityTintColor}
  35. ]} >
  36. {title}
  37. </Text>
  38. <Image
  39. source={checkImage}
  40. style={{tintColor: this.props.activityTintColor ? this.props.activityTintColor : this.defaultConfig.activityTintColor}} />
  41. </View>
  42. );
  43. } else {
  44. return (
  45. <View style={{flex: 1, justifyContent: 'space-between', alignItems: "center", paddingHorizontal: 15, flexDirection: 'row'}} >
  46. <Text style={[
  47. styles.item_text_style,
  48. this.props.optionTextStyle,
  49. {color: this.props.tintColor ? this.props.tintColor : this.defaultConfig.tintColor}
  50. ]} >{title}</Text>
  51. </View>
  52. );
  53. }
  54. }
  55. renderActivityPanel() {
  56. if (this.state.activityIndex >= 0) {
  57. var currentTitles = this.props.data[this.state.activityIndex];
  58. var heightStyle = {};
  59. if (this.props.maxHeight && this.props.maxHeight < currentTitles.length * 44) {
  60. heightStyle.height = this.props.maxHeight;
  61. }
  62. return (
  63. <View style={{position: 'absolute', left: 0, right: 0, top: 40, bottom: 0}}>
  64. <TouchableOpacity onPress={() => this.openOrClosePanel(this.state.activityIndex)} activeOpacity={1} style={{position: 'absolute', left: 0, right: 0, top: 0, bottom: 0}}>
  65. <View style={{opacity: 0.4, backgroundColor: 'black', flex: 1 }} />
  66. </TouchableOpacity>
  67.  
  68. <ScrollView style={[{position: 'absolute', top: 0, left: 0, right: 0, backgroundColor: 'white'}, heightStyle]} >
  69. {
  70. currentTitles.map((title, index) =>
  71. <TouchableOpacity key={index} activeOpacity={1} style={{flex: 1, height: 44}} onPress={this.itemOnPress.bind(this, index)} >
  72. {this.renderChcek(index, title)}
  73. <View style={{backgroundColor: '#F6F6F6', height: 1, marginLeft: 15}} />
  74. </TouchableOpacity>
  75. )
  76. }
  77. </ScrollView>
  78. </View>
  79. );
  80. } else {
  81. return (null);
  82. }
  83. }
  84. openOrClosePanel(index) {
  85. this.props.bannerAction ? this.props.bannerAction() : null;
  86. // var toValue = 0.5;
  87. if (this.state.activityIndex == index) {
  88. this.closePanel(index);
  89. this.setState({
  90. activityIndex: -1,
  91. });
  92. // toValue = 0;
  93. } else {
  94. if (this.state.activityIndex > -1) {
  95. this.closePanel(this.state.activityIndex);
  96. }
  97. this.openPanel(index);
  98. this.setState({
  99. activityIndex: index,
  100. });
  101. // toValue = 0.5;
  102. }
  103. // Animated.timing(
  104. // this.state.rotationAnims[index],
  105. // {
  106. // toValue: toValue,
  107. // duration: 300,
  108. // easing: Easing.linear
  109. // }
  110. // ).start();
  111. }
  112. openPanel(index) {
  113. Animated.timing(
  114. this.state.rotationAnims[index],
  115. {
  116. toValue: 0.5,
  117. duration: 300,
  118. easing: Easing.linear
  119. }
  120. ).start();
  121. }
  122. closePanel(index) {
  123. Animated.timing(
  124. this.state.rotationAnims[index],
  125. {
  126. toValue: 0,
  127. duration: 300,
  128. easing: Easing.linear
  129. }
  130. ).start();
  131. }
  132. itemOnPress(index) {
  133. if (this.state.activityIndex > -1) {
  134. var selectIndex = this.state.selectIndex;
  135. selectIndex[this.state.activityIndex] = index;
  136. this.setState({
  137. selectIndex: selectIndex
  138. });
  139. if (this.props.handler) {
  140. this.props.handler(this.state.activityIndex, index);
  141. }
  142. }
  143. this.openOrClosePanel(this.state.activityIndex);
  144. }
  145. renderDropDownArrow(index) {
  146. var icon = this.props.arrowImg ? this.props.arrowImg : this.defaultConfig.arrowImg;
  147. return (
  148. <Animated.Image
  149. source={{uri:icon}}
  150. style={{
  151. width:6,
  152. height:4,
  153. marginLeft: 8,
  154. tintColor: (index === this.state.activityIndex) ? (this.props.activityTintColor ? this.props.activityTintColor : this.defaultConfig.activityTintColor) : (this.props.tintColor ? this.props.tintColor : this.defaultConfig.tintColor),
  155. transform: [{
  156. rotateZ: this.state.rotationAnims[index].interpolate({
  157. inputRange: [0, 1],
  158. outputRange: ['0deg', '360deg']
  159. })
  160. }]
  161. }} />
  162. );
  163. }
  164. render() {
  165. return (
  166. <View style={{flexDirection: 'column', flex: 1}} >
  167. <View style={{
  168. flexDirection: 'row',
  169. backgroundColor: this.props.bgColor ? this.props.bgColor : this.defaultConfig.bgColor}} >
  170. {
  171. this.props.data.map((rows, index) =>
  172. <TouchableOpacity
  173. activeOpacity={1}
  174. onPress={this.openOrClosePanel.bind(this, index)}
  175. key={index}
  176. style={{flex: 1, height: 48, alignItems: "center", justifyContent: "center"}} >
  177. <View style={{flexDirection: 'row', alignItems: "center", justifyContent: "center"}} >
  178. <Text
  179. style={[
  180. styles.title_style,
  181. this.props.titleStyle,
  182. {color: (index === this.state.activityIndex) ?
  183. (this.props.activityTintColor ? this.props.activityTintColor : this.defaultConfig.activityTintColor)
  184. :
  185. (this.props.tintColor ? this.props.tintColor : this.defaultConfig.tintColor)}
  186. ]} >
  187. {rows[this.state.selectIndex[index]]}
  188. </Text>
  189. {this.renderDropDownArrow(index)}
  190. </View>
  191. </TouchableOpacity>
  192. )
  193. }
  194. </View>
  195. {this.props.children}
  196. {this.renderActivityPanel()}
  197. </View>
  198. );
  199. }
  200. }
  201. DropdownMenu.propTypes = {
  202. bgColor: PropTypes.string,
  203. tintColor: PropTypes.string,
  204. activityTintColor: PropTypes.string,
  205. arrowImg: PropTypes.number,
  206. checkImage: PropTypes.number,
  207. data: PropTypes.array,
  208. bannerAction: PropTypes.func,
  209. optionTextStyle: PropTypes.object,
  210. titleStyle: PropTypes.object,
  211. maxHeight: PropTypes.number
  212. }
  213. const styles = StyleSheet.create({
  214. title_style: {
  215. fontSize: 16
  216. },
  217. item_text_style: {
  218. color: '#fdd000',
  219. fontSize: 16
  220. }
  221. });
  222. export default DropdownMenu;
下拉列表封装

  如何使用?

  1. render() {
  2. var data = [["分类", "分类", "分类", "分类"], ["价格", "价格"], ["筛选", "筛选"]];
  3. return (
  4. <View style={{flex: 1}}>
  5. <View style={styles.dropMenu}/>
  6. <DropMenu
  7. style={{flex:1}}
  8. bgColor={'white'}
  9. tintColor={'#666666'}
  10. activityTintColor={'#fdd000'}
  11. // arrowImg={}
  12. // checkImage={}
  13. // optionTextStyle={{color: '#333333'}}
  14. // titleStyle={{color: '#333333'}}
  15. // maxHeight={300}
  16. handler={(selection, row) => this.setState({text: data[selection][row]})}
  17. data={data}
  18. >
  19.  
  20. <ListView
  21. style={styles.listViewStyle}
  22. dataSource={this.state.dataSource}
  23. renderRow={this.renderRow}
  24. />
  25.  
  26. </DropMenu>
  27. </View>
  28. );
  29. }
下拉列表的使用

  6、React Native项目中“A+ListView”或“ListView + B”的界面搭建

  项目中ScrollView嵌套ListView会造成手势滑动冲突,可以使用“A+ListView”或“ListView + B”的样式进行搭建,

  通过:ListView的header或footer来实现。

  7、地图展示  

  项目中使用的通过jsp API接入到高德地图。

二、技术难点

  1、组件化思想

  React Native是React在移动端的跨平台方案。如果想更快地理解和掌握React Native开发,就必须先了解React。

  React是FaceBook开源的一个前端框架,它起源于 Facebook 的内部项目,并于 2013 年 5 月开源。因为React 拥有较高的性能,代码逻辑非常简单,所以越来越多的人已开始关注和使用它,目前该框架在Github上已经有7万+star。

  React采用组件化的方式开发,通过将view构建成组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。有一句话说的很形象:在React中,构建应用就像搭积木一样。

  React认为一个组件应该具有以下特征:
  •  可组合:一个组件易于和其他组件一起使用,或者嵌套在另一个组件内部。如果一个组件内部创建了另外一个组件,那么父组件拥有它创建的子组件,通过这个特性,一个复杂的UI可以拆分成多个简单的UI组件;
  •    可重用:每个组件都是具有独立功能的,它可以被使用在多个UI场景;
  •    可维护:每个小的组件仅仅包含自身的逻辑,更容易被理解和维护。

  2、组件的属性与状态

  在React Native里,组件所持有的数据分为两种:

  1、属性(props):组件的props是不可变的,它只能从其他的组件(例如父组件)传递过来。

  2、状态(state):组建的state是可变的,它负责处理与用户的交互。在通过用户点击事件等操作以后,如果使得当前组件的某个state发生了改变,那么当前组件就会触发render()方法刷新自己。

  props:

  由于props是从其父组件传递过来的,那么可想而知,props的声明应该是当前组件的父组件来做。

  3、组件的生命周期

  请参考组件的生命周期

  4、搭建APP的框架:Tab Navigator 和 Stack Navigator  

  请参考学习:React Navigation的应用

  5、组件间通信

  组件间通信分为两大类;

  1、有直接关系或间接关系的组件之间通信

  2、无直接关系或间接关系的组件之间通信

原文链接:http://www.cnblogs.com/xjf125/p/10973135.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号