React-native 知识点累积

3,811 阅读7分钟

不积跬步无以至千里,不积小流无以成将海!

VIN扫码,传递的参数值被覆盖

  • 解决方法:

在页面关闭前,将监听移除

DeviceEventEmitter.removeListener('SmartVisionResult',this.smartVisionResult);
DeviceEventEmitter.removeListener('EventReminder', this.smartVisionResultIos);

react-native-scrollable-tab-view使用问题

  • 问题:设计需求,在tab的最右侧放置一个按钮

react-native-scrollable-tab-view 默认占据一整行,在右侧要放置一个按钮,我最开始的做法是在eact-native-scrollable-tab-view的最后一个放置一个空的标签,将按钮浮动在ScrollableTabView的右顶部,但是这个方法会导致滑动到最后一个位置时,此tab页面为空白页。类似以下布局:

tab内容区域
  • 解决方案:

下载以下链接的JS文件,并修改成自己要的需求

参考链接:github.com/ptomasroos/…

初学者易入的坑

以下是自身从入门到实战,所遇到的坑的一个记录:

  • 布局的适配

我们公司的设计是以iPhone6的尺寸设计的,例如有一个内容区域,设计稿是351pt的宽度,那么在代码中,可通过减去内容距离两遍的宽度,获取内容的宽度,例:width: (width-12-12)。如果直接写成width: 351,在小屏幕的设备中会有问题。

  • Text的使用

文字需要放在Text标签中,否则会报错,Text的样式也要谨慎书写,不然在ios中样式与Android的不一致

<Text style={style.textStyle}>Text左边有绿色边框</Text>
textStyle: {
    color: '#999';
    fontSize: 14,
    borderLeftWidth: 5,
    borderLeftColor: 'green'
},

以上代码,在Android中,左边会有绿色的边框,但是在iOS中,绿色边框就消失了。 解决方法:在Text标签外面在包一层View标签,来写绿色边框的样式。

  • Text多行显示(个人项目中,大于等于3行,就会有此问题),在某些手机(例:小米)中,最后一行会有显示不全的问题

通过网上查找和技术群里请教,有以下几种解决方法:

1、/n:在末尾加 ‘/n’,通过换行解决此问题。

2、paddingVertical: 给Text标签的样式设置paddingVertical属性

React-native 搜索高亮

  • 代码示例
//搜索高亮--js
_searchHightColor(searchText,originText){
    let reg1 = new RegExp(searchText, "g");
    return (
     <Text>
            {
                (''+originText+'').replace(reg1,' '+searchText+' ').split(' ').map((item,index)=>{  //将 ‘搜索的关键字’ 替换成,空格 + 关键字 + 空格 的字符串,在使用 ‘空格’ 将字符串分割成数组形式
                    if(reg1.test(item) && searchText!=''){
                        return (
                            <Text key={index} style={[styles.hightTextColor]}>{ item }</Text>
                        )
                    }else{
                        return (
                            <Text>{ item }</Text>
                        )
                    }
                })
            }
        </Text>
    );
}

//搜索高亮--页面
<Text>{this._searchHightColor(this.state.key,data.mobile)}</Text>
  • 思路

将 ‘搜索的关键字’ 替换成,空格 + 关键字 + 空格 的字符串,在使用 ‘空格’ 将字符串分割成数组形式。。

备注:本项目中,使用 ‘空格’ 作为区分即可,大家可根据自己的项目需求进行分割。。如果有更好的方法,欢迎提供。

WebView的使用

  • 项目中,由于配置的问题,导致使用 import { WebView } from 'react-native-webview' 方式引入,一片红,运行会报错,最终使用以下形式引入WebView组件:

    import {
      WebView
    } from 'react-native';
    
  • 使用方法:

    //例:
    const BaseScript =
      `
    const meta = document.createElement('meta'); 
    meta.setAttribute('content', 'width=device-width,initial-scale=1.0, maximum-scale=1.0, user-scalable=0'); 
    meta.setAttribute('name', 'viewport'); 
    document.getElementsByTagName('head')[0].appendChild(meta); 
    (function () {
    var height = null;
    function changeHeight() {
    if (document.body.scrollHeight != height) {
      height = document.body.scrollHeight;
      if (window.postMessage) {
        window.postMessage(JSON.stringify({
          type: 'setHeight',
          height: height,
        }))
      }
    }
    }
    setTimeout(changeHeight, 300);
    } ())
    `
    export default class Page extends BasePage {
      constructor(props) {
          super(props);
          this.state = {
              content: '<p style='font-size:12px;'>哈哈哈哈哈</p>',  //WebView要显示的内容【html标签字符串或地址】
          };
      }
      /**
       * web端发送过来的交互消息
       */
      onMessage(event) {
          try {
              const action = JSON.parse(event.nativeEvent.data)
              if (action.type === 'setHeight' && action.height > 0) {
                  this.setState({ WebViewHeight: action.height })
              }
          } catch (error) {
              // pass
          }
      }
      renderPage(){
          return (
              <View style={[styles.comContainer]}>
                  <ScrollView style={[styles.serviceHelpScroll]}>
                      <WebView
                          style={{ marginBottom: 10, height: this.state.WebViewHeight, width: width }}
                          injectedJavaScript={BaseScript}
                          scalesPageToFit={false}
                          scrollEnabled={false}
                          // source={{ uri: global.Http.host + '/' + this.state.content }}  //.html地址形式
                          originWhitelist={['*']}
                          source={{ html:  this.state.content,baseUrl:'' }}  //即使没有baseUrl,也要加上这个属性,写上空串,解决中文乱码的问题!  html标签形式
                          onMessage={this.onMessage.bind(this)}
                      />
                     
                  </ScrollView>                
              </View>
          )
      }
    }
    

    备注:直接使用 html 标签的字符串,若含有中文,会出现中文乱码的问题。。解决方法:source={{ html: this.state.content,baseUrl:'' }}
    baseUrl:'' 一定要写,就可以解决此问题。。

适配 ‘刘海屏’

//最外围的容器
 commonWrap: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: global.gDevice.isIPhoneX ? 34 : 0,  //重要
    backgroundColor: '#f6f6f6',
    flex: 1,
  },
  
//底部tab栏
foot: {
    width: width,
    height: 49,
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: '#FFFFFF',
    borderBottomWidth: StyleSheet.hairlineWidth,
    borderBottomColor: '#EEEEEE',
  },
  
  //例:
  <View style={[styles.commonWrap]}>
  	<ScrollView>
  		//页面内容
  	</ScrollView>
  	<View style={[styles.foot]}>
  		//底部tab栏
  	</View>
  </View>

备注:global.gDevice.isIPhoneX 的来源global.gDevice.isIPhoneX 是全局变量。可以在设置全局变量的文件中,定义需要的变量。

const OS = Platform.OS;
const ios = (OS == 'ios');
const android = (OS == 'android');
const isIPhoneX = (ios && height == 812 && width == 375);
global.gDevice = {
    ios: ios,
    android: android,
    isIPhoneX: isIPhoneX,
}

TextInput 表单在IOS的问题

  • 输入框文字错位的问题:

解决方法:不能设置 height 和 lineheight ,否则,在IOS下会出现 输入值偏下(错位)的问题。

  • Android和IOS输入框兼容问题:

解决方法:使用padding:0,使IOS和Android样式保持一致。

  • IOS输入时,首个文字被遮挡的问题:

解决方法:给TextInput添加 paddingLeft:5 的属性值。

React-native Text首行缩进

解决方法的参考链接:blog.csdn.net/r122555/art…

项目启动时,提示找不到某些包

  • 场景重现

例如:npm install --save react-native-webview

备注:react-native-webview会报错。问题是此组件没有安装。react-native link react-native-webview 也无效。 目前的解决方法: 使用 React-native 自带的 WebView 组件

复制

//引入
import {
    Clipboard
} from 'react-native';

//使用
<TouchableOpacity onPress={()=>{ 
	Clipboard.setString(this.state.authCode);
    this.showInfo('复制成功') 
}} style={[comStyles.centerCopyBtn]}>
    <Text>复制</Text>
</TouchableOpacity>

备注:可以查一下 Clipboard 的使用

拨号

//引入
import {
    Linking
} from 'react-native';

//使用
//js
/拨打电话
linking = (tel) => {
    if(tel && tel.indexOf('tel:')<0){
        tel='tel:' + tel;
    }
	Linking.canOpenURL(tel).then(supported => {
        if (!supported) {
           console.log('Can\'t handle url: ' + tel);
        } else {
           return Linking.openURL(tel);
       }
	}).catch(err => console.error('An error occurred', err));
}
//JSX
<TouchableOpacity style={{flex: 1,alignSelf: 'center',}} onPress={() => { this.linking('tel:' + 100100100) }}>
	<Text selectable={true} dataDetectorType="phoneNumber">400-9933-139</Text>
</TouchableOpacity>

备注: this.linking('tel:' + 100100100) 中 tel 后面必须跟数字,不能包含非数字的字符

20200901更新

小米手机 边框线 StyleSheet.hairlineWidth 不显示的问题

解决方法:

import {
    PixelRatio,
} from 'react-native';

borderBottomWidth:PixelRatio.get() >= 3 ? 0.5 : 1

react-native-swipe-list-view 组件 左滑删除的问题

  • 问题:高度不一致时,删除后,会保留删除那个的高度,并把高度赋值给下一个,导致样式错乱的问题
  • 解决方法:加上这个属性 recalculateHiddenLayout={true} 缺点:消耗性能
例:
<SwipeRow ref={'packRowsItem_'+item.id} recalculateHiddenLayout={true} rightOpenValue={-64} stopRightSwipe={-64} disableRightSwipe={true}  closeOnRowPress={true}></SwipeRow>

react-native-sectioned-multi-select 下拉框组件,修改成自己想要的样式

  • 引入:

import SectionedMultiSelect from 'react-native-sectioned-multi-select';

  • 样式修改:可参考以下
//下拉框 样式自定义
<SectionedMultiSelect
    items={this.props.shopList}
    ...
    //自己可修改 start
    headerComponent={
      <View style={{flexDirection:'row',alignItems:'center',justifyContent:'center',marginTop:15}}>
          <Text style={{color: '#323232',fontSize: 16,fontWeight:'bold'}}>调入门店</Text>
      </View>
    }
    cancelIconComponent={
    	<Text style={{color: '#777777',fontSize: 13,fontWeight:'bold'}}>取消</Text>
    }
    //下拉框右侧图标
    selectToggleIconComponent={
        <Image style={style.cMultiToggleIcon} source={require('../common/components/img/btn_erp_list_more.png')}/>
    }
    //搜索输入图标
    searchIconComponent={
        <Image style={style.cMultiSearchIcon} source={require('../common/components/img/btn_erp_search.png')}/>
    }
    //选中图标
    selectedIconComponent={
    	<Image style={{width:15,height:15}} source={require('../../common/components/img/customer/btn_erp_list_s.png')}/>
    }
    //未选中图标
    unselectedIconComponent={
    	<Image style={{width:15,height:15}} source={require('../../common/components/img/customer/btn_erp_list_nor.png')}/>
    }
    styles={{
      //显示的input框的样式 start
      selectToggleText: {
      	color: ((this.props.billDate && this.props.billDate.toShop && this.props.billDate.toShop.name)||this.state.toShopNames)?'#202020':'#999999',
      	fontSize: 12,
      	textAlign: 'left',
      },

      selectToggle:{
      	height: 25,
      	flexDirection: 'row',
      	justifyContent: 'flex-start',
      },
      //显示的input框的样式 end
      //遮罩
      backdrop: {
      	justifyContent:'center',
      	alignItems:'center'
      },
      //白色内容区域
      container: {
      	maxHeight: (height-200),
      	width: width-105,
      	alignSelf:'center'
      },
      //搜索框-bar
      searchBar: {
      	backgroundColor: '#F5F5F5',
      	width: width-131,
      	alignSelf:'center',
      	// height: 25,
      	borderRadius: 5,
      	padding: 0,
      	paddingTop: 0,
      	paddingBottom: 0,
      	paddingLeft: 0,
      	paddingRight: 0,
      	marginTop: 15,
      	marginBottom: 5,
      	flexDirection: 'row',
      	justifyContent:'center'
      },
      //搜索框-icon
      center: {
      	marginLeft: -10,
      	flexDirection: 'row',
      	justifyContent:'center',
      	paddingRight: 0,
      	paddingLeft: 0,
      	alignItems:'center',
      },
      //搜索框-input
      searchTextInput: {
      	// backgroundColor: 'yellow',
      	flex: 1,
      	textAlign:'left',
      	margin: 0,
      	padding: 0,
      	paddingRight: 0,
      	paddingTop:0,
      	paddingBottom: 0,
      	height: 25,
      	marginRight: 10,
      	marginLeft: 0,
      	textAlignVertical:'center',
      	fontSize: 12,
      	marginLeft: -10
      },
      //分割线
      separator: {
      	backgroundColor: '#fff'
      },
      item: {
      	height: 34,
      	width: width-145,
      	alignSelf:'center',
      },
      itemText: {
      	color: '#777777',
      	fontSize: 12,
      	fontWeight:'normal'
      },
      selectedItemText: {
      	color: '#202020',
      	fontSize: 12,
      	fontWeight:'normal'
      },
      button: {
      	width: (width-155)/2,
      	height: 38,
      	borderRadius: 19,
      	justifyContent:'center',
      	alignItems:'center',
      	backgroundColor: '#FD9F01',
      	marginRight: 20,
      	marginTop: 20,
      	marginBottom: 15
      },
      confirmText: {
      	color: '#FFFFFF',
      	fontSize: 13,
      },
      //取消按钮
      cancelButton: {
      	width: (width-155)/2,
     	height: 38,
      	borderRadius: 19,
      	backgroundColor: '#fff',
      	justifyContent:'center',
      	alignItems:'center',
      	borderWidth: StyleSheet.hairlineWidth,
      	borderColor: '#CFCFCF',
     	marginLeft: 20,
     	marginRight: 10,
      	marginTop: 20,
      	marginBottom: 15
      },
      itemIconStyle: {
      	backgroundColor: 'pink'
      },
    }}
    //自己可修改 end
/>

备注:备注:具体请参考 github 的API文档

需要修改下以下两个文件(原因:加了“取消”按钮)

机型:Redmi K30,由于刘海屏问题,导致顶部按钮无法点

  • 图片

备注:由于公司没有此机型的测试机,此图来自于客户手机,图不清晰。此图红色标注部分是按钮

  • 解决方法
import { Dimensions, Platform, StatusBar } from 'react-native';
const statusBarHeight = (ios ? (isIPhoneX ? 44 : 20) : StatusBar.currentHeight);

<View style={[{ width: width, height: statusBarHeight) }]}></View>
<View style={[{
    width: width,
    height: 44,
    backgroundColor: this.props.navBarColor || '#fff',//背景色,默认白色
    flexDirection: 'row',//横向排
    justifyContent: 'space-between',//主轴对齐方式
    alignItems: 'center',//次轴对齐方式(上下居中)
    borderBottomWidth: this.props.borderBottomWidth || 0,//是否有下边框
    borderColor: this.props.borderColor || '#a3a3a3',
}]}>
	...
</View>
                

后续项目中遇到react-native相关的问题和知识点都会更新至此文!若有错误,欢迎指出!