react native社区项目知识点

前言

本来想的上一个React项目做完,从容过完1月迎接新年,IT行业的快节奏真是不容许有这种想法;公司把3月上线的react native项目,时间周期活生生压缩到1月底,真是哭笑不得。这样只能加加班而且保质保量地完成,还是在接口各种报错的前提下利用Mock数据。 言归正传,回到react native项目中来

xcode配置篇

一、iOS APP图标配置

二、iOS启动页配置、各种尺寸封面大小

TabBar配置篇

一、iPhone X 适配小技巧

  • 应对iphone刘海屏statusbar颜色处理,利用SafeAreaView包裹整个render
    <SafeAreaView style={{backgroundColor:'red'}}></SafeAreaView>
复制代码
  • 上面方法虽然能达到效果,但除了statusbar,整个背景都会被color覆盖,解决办法如下。(附上stackoverflow参考链接
    <Fragment>
      <SafeAreaView style={{ flex:0, backgroundColor: 'red' }} />
      <SafeAreaView style={{ flex:1, backgroundColor: 'gray' }}>
        <View style={{ flex: 1, backgroundColor: 'white' }} />
      </SafeAreaView>
    </Fragment>
复制代码

二、createBottomTabNavigator 个性化图标

1、所需要显现的效果,中间“检测”图标比较难定位

2、代码
    import { createBottomTabNavigator, createAppContainer, createStackNavigator } from 'react-navigation' // 引入依赖
    
    const TabNavigator = createBottomTabNavigator({
      Home: {
        screen: Home,
        navigationOptions:()=>({
          title:'首页',
          tabBarIcon: ({tintColor,focused}) => (
            focused ?
              <Image source={require('...')} style={style.nav_icon}/> :
              <Image source={require('...')} style={style.nav_icon}/>
          )
        }),
      },
      Community: {
        screen: Community,
        navigationOptions:()=>({
          title:'社区',
          tabBarIcon: ({tintColor,focused}) => (
            focused ?
              <Image source={require('...')} style={style.nav_icon}/> :
              <Image source={require('...')} style={style.nav_icon}/>
          ),
          tabBarOnPress: ({ navigation, defaultHandler }) => {
            /** 触发器
             * defaultHandler()、navigation.navigate('Community')
             * 两个方法都能实现相同效果,跳转至 Community Component
             */
            defaultHandler()
            navigation.state.params.triggerAvatar()
          }
        })
      },
      Detection: {
        screen: Detection,
        navigationOptions:()=>({
          title:'检测',
          tabBarLabel: ({tintColor,focused}) => (
            focused ?
              <ImageBackground
                resizeMode="cover"
                source={require('...')}
                imageStyle={styles.midIcon_img_wrap}
                style={styles.midIcon_wrap}>
                <Image source={require('...')} style={styles.midIcon}/>
                <Text style={styles.midIcon_word}>检测</Text>
              </ImageBackground>
              :
              <ImageBackground
                resizeMode="cover"
                source={require('...')}
                imageStyle={styles.midIcon_img_wrap}
                style={styles.midIcon_wrap}>
                <Image source={require('...')} style={styles.midIcon}/>
                <Text style={styles.midIcon_word}>检测</Text>
              </ImageBackground>
          )
        }),
      },
      Recover: {
        screen: Recover,
        navigationOptions:()=>({
          title:'康复',
          tabBarIcon: ({tintColor,focused}) => (
            focused ?
              <Image source={require('...')} style={style.nav_icon}/> :
              <Image source={require('...')} style={style.nav_icon}/>
          )
        }),
      },
      Me: {
        screen: Me,
        navigationOptions:()=>({
          title:'我的',
          tabBarIcon: ({tintColor,focused}) => (
            focused ?
              <View style={style.nav_icon_wrap}>
                <Image source={require('...')} style={style.nav_icon}/>
                <MsgSpot/>
              </View>
              :
              <View style={style.nav_icon_wrap}>
                <Image source={require('...')} style={style.nav_icon}/>
                <MsgSpot/>
              </View>
          )
        })
      }
    },{
      initialRouteName:'Home', // 路由最开始访问
      lazy:true,               // 是否懒加载
      tabBarOptions:{
        activeTintColor:'#0168F5',
        style:{
          borderTopWidth:0,
          shadowOpacity: 0.1,
          shadowRadius: 5,
          shadowColor: '#8B8B8B',
          shadowOffset:{ width:0,height:-4 },
          paddingHorizontal:16
        },
        labelStyle:{fontSize:10,position:'relative',top:-2},
        tabStyle:{paddingTop:2}
      }
    })
    
    //StackNavigator
    const App = createStackNavigator({
      TabNavigator: {screen: TabNavigator, navigationOptions: () => ({gesturesEnabled: true,header: null})},
      HomeDetail: {screen: HomeDetail, navigationOptions: () => ({gesturesEnabled: true,header: null})}
    })
    
    console.disableYellowBox = true // 屏蔽warning弹窗
    export default createAppContainer(App)
复制代码

三、TabNavigator站内消息提示小红点

思路:这种跨组件间事件操作,可以利用Redux实现,但官方给出的是最新版本不会默认集成,那么就自己找方法怎么简单怎么来,首先考虑到的是DeviceEventEmitter

import { DeviceEventEmitter } from 'react-native' // 引入
复制代码
// spot红点事件注册
class MsgSpot extends Component<Props> {
  state = { spotShow:false }
  componentDidMount(){  // tabbar首次渲染订阅事件
    DeviceEventEmitter.addListener('message',param => {
      this.setState({spotShow:param.spotShow})
      console.log(param)
    })
  }
  render() {
    const {spotShow} = this.state
    return (
      <Fragment>
      {spotShow?<View style={[style.redSpot,style.redSpot_nav]}></View>:null}
      </Fragment>
    )
  }
}
复制代码
DeviceEventEmitter.emit('message', {spotShow:true/false}) // 触发事件
复制代码

四、TabNavigator点击触发事情

// 详情看上面tabbar
tabBarOnPress: ({ navigation, defaultHandler }) => {
/** 触发器
 * defaultHandler()、navigation.navigate('Community')
 * 两个方法都能实现相同效果,跳转至 Community Component
 */
defaultHandler()
navigation.state.params.triggerAvatar()
}
复制代码

五、页面订阅事件

componentDidMount(){
    // 订阅生命周期
    this._listeners = this.props.navigation.addListener('willFocus', ()=>this.xxx())
}
componentWillUnmount(){
    this._listeners.remove() // 移除事件订阅
}
复制代码

react-navigation链接参考

六、导航callback与导航事件注册

// 跳转前页面
startScan = (param) => {}     // 1、注册回调
navigate('xxx',{ startScan:this.startScan ,callback:()=>{}})

// 跳转后 xxx 页面
state.params.startScan(param) // 1、触发回调
state.params.callback({})     // 2、触发callback    
复制代码

滚动事件、布局篇

一、底部按钮与ScrollView样式

<SafeAreaView style={{flex:1}}>
    <ScrollView></ScrollView>
    <Text>Button</Text>
</SafeAreaView>
复制代码

二、FlatList 上拉、下拉实现

import {
  FlatList,
  RefreshControl
} from 'react-native'   // 引入

constructor(props){
super(props)
this.dataListFake = []  // 列表数据
this.page     = 1       // 页码
this.state = {
  dataList : [],        // 渲染数据
  refresh : true,
  pullDown: false,
  isLast:   false,
  loading:  false       // 正在加载
}
}
componentDidMount() {
    this._onRefresh()
}
renderItem = ({item}) => { return () }
renderFooter = () => {
// 显示时机
// 1、刚开始加载、之后,不显示
// 2、下刷新,消失
// 3、上拉加载,动画出现
//    加载完,动画消失;没有数据,显示"暂无更多"
const { pullDown, isLast } = this.state
return (
      <View style={[style.footLoad,{paddingBottom:200}]}>
        {pullDown?<Image source={require('../../assets/loading.gif')} style={style.footImg}/>:null}
        {isLast?<Text style={style.footWord}>暂无更多~</Text>:null}
      </View>
    )
}
renderEmpty = () => {
    return (
        <View style={style.renderEmpty}>
            <Text>暂无数据</Text>
        </View>
    )
}

// 下拉刷新
_onRefresh = () => {
    const {loading} = this.state
    // 是否正在loading
    if (!loading){
      this.page = 1
      this.dataListFake = []
      this.setState({refresh:true,isLast:false})
      this.dataList(dataListCallBack)
    }
    function dataListCallBack(){
      // Toast.success('刷新成功',800)
    }
}

// 上拉加载
_onEndReached = () => {
    return false // 没有分页
    const {isLast,loading} = this.state
    if (!loading){// 是否正在loading
      if (isLast){
        // Toast.sad('暂无更多数据~')
      }else{
        this.page++
        this.setState({pullDown:true})
        this.dataList(dataListCallBack)
      }
    }
    function dataListCallBack(){
      // Toast.message(`第${_this.page}页`,null,'center')
    }
}

  // 网络请求
  async dataList(callBack) {
    try {
      this.setState({loading:true})
      ...
      let data = {
        ...,
        page:this.page,
        r:10
      }
      let data_string = queryString.stringify(data)
      let url = ...+'?'+data_string
      const response = await axios.get(url)
      setTimeout(()=>{this.setState({loading:false})},800) // complete

      let code = Number(response.data.code)
      let info = response.data.info

      if (code===0){
        let dataList = response.data.data
        this.dataListFake = this.dataListFake.concat(dataList)
        this.setState({dataList:this.dataListFake})
      }else if (code===9000){ // 根据接口情况而定
        setTimeout(()=>{this.setState({isLast:true})},800)
      }else{
        Toast.sad(info)
      }
      setTimeout(()=>{
        this.setState({
          refresh:false,
          pullDown:false
        }) // 不管数据请求如何,状态归位
      },800)

      console.log(response.data)
      console.log(this.page)
      callBack()  // 假回调

    } catch (error) {
      this.setState({refresh:false,pullDown:false,loading:false})
      Toast.fail('网络请求异常')
    }
  }
复制代码
render() {
    const { dataList, refresh } = this.state
    return (
      <SafeAreaView style={[style.container,{flex:1}]}>
        <StatusBar barStyle="dark-content"/>
        <FlatList
          contentContainerStyle={styles.introduction}
          data={ dataList }
          renderItem={this.renderItem}
          ListFooterComponent={this.renderFooter}
          ListEmptyComponent={this.renderEmpty}
          keyExtractor={this._keyExtractor}
          onEndReached={ this._onEndReached }
          onEndReachedThreshold={0}
          refreshing={refresh}
          refreshControl={
            <RefreshControl
              refreshing={ refresh }
              colors={['#ff0000', '#00ff00', '#0000ff']}
              progressBackgroundColor={"#ffffff"}
              onRefresh={ this._onRefresh }
            />
          }
        />
      </SafeAreaView>
    )
  }

复制代码

loading.gif

杂文篇

一、条形码扫描 iOS版本

react-native-smart-barcode可以解决大部分问题,集成时因为propTypes的引入没有兼容高版本导致报错,可以去Barcode.js注释掉static propTypes

// 同时利用页面订阅,达到每次显示页面重新扫描的目的
this._listeners = this.props.navigation.addListener('didFocus', ()=> this._startScan())
复制代码

二、富文本解析显示 react-native-htmlview

import HTMLView from 'react-native-htmlview' // 引入
复制代码
<HTMLView
    value={htmlContent}
    addLineBreaks={false} // 去掉每行之间的空格
    stylesheet={styles}/>
复制代码
  p:{
    color:'#666666',
    fontSize:15,
    fontWeight:'400',
    lineHeight:20,
    paddingHorizontal: 0,
    marginTop:5,
    marginBottom:5
  }
复制代码

三、swiper滑动应用 react-native-swiper

四、上传多图

要注意的是传多图时axios需要配置的地方

let config = {headers:{'Content-Type':'multipart/form-data'}}
let formData=new FormData()
xxx.forEach((val,key)=>{
  let file = {uri:val.path,type:val.mime,name:val.filename?val.filename:'CAMERA_PHOTO.JPG'}
  formData.append(`img${key}`,file)
})
await axios.post(url,formData,config)
复制代码

五、调起打电话

Linking.openURL(`tel:110`)
复制代码

六、react-native-image-crop-picker图片上传遇到的iOS原生问题

1、cd /guyu/ios/podfile
2、cocoapods 安装配置
	sudo gem install cocoapods
	pod setup
	cd ios
	pod init
# 3、配置下面文件
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
# 添加至pod文件里面的配置
target 'guyu' do
    pod 'RSKImageCropper'
    pod 'QBImagePickerController'
end
复制代码

七、axios处理GET时,URL拼接 query-string

query-string更方便拼接url进行Get请求,也方便从url里面解析出键值对来

NPM库

  1. teaset yarn add teaset
  2. react-native-actionsheet yarn add react-native-actionsheet
  3. react-native-fit-image yarn add react-native-fit-image

猜你喜欢

转载自juejin.im/post/5c5402f8f265da2dbd7fd084