RN 从上手到“摒弃”

RN 从上手到“摒弃”

媒介: react-native,相对于近来🔥的飞起的flutter,不算是一个新手艺,2015年Facebook 开源,到如今已4 5 个岁首,一直在保护当中,然则至今未宣布 v1 版本,如今已更新到0.59。 该手艺目的: 跨平台完成原生运用。 GitHub start 数量: 77602(2019-5-29)。
《RN 从上手到“摒弃”》
文章内,图片许多,占有了肯定的篇幅。班门弄斧之作,如有大神见到,敬请指教,有不对不合理的地方,敬请指出!我是迩伶贰!

正文

github地点: https://github.com/adouwt/rea…

nodejs背景:https://github.com/adouwt/nod…

1、项目预览

如今已完成的功用展现:
《RN 从上手到“摒弃”》

入手demo项目,本盘算模拟微信的功用做一遍。如今已完成微信的一级界面。截图以下:
首页:

《RN 从上手到“摒弃”》

通信录:

《RN 从上手到“摒弃”》

发明:

《RN 从上手到“摒弃”》

我:

《RN 从上手到“摒弃”》

朋友圈(上拉加载和下拉革新):
(未完成,就是挪用了接口)

《RN 从上手到“摒弃”》

谈天界面:

《RN 从上手到“摒弃”》

摄像头拍照(安卓虚拟机):

《RN 从上手到“摒弃”》

项目重要运用插件(库):

  1. react-native-camera (挪用摄像头)
  2. react-native-vector-icons (图标库)
  3. react-navigation (路由导航)

参考材料:

2、项目运转

~条件: 环境搭建及相干软件、安卓或许ios 的模拟器装置, 参考官网即可,https://reactnative.cn/docs/g…

git clone https://github.com/adouwt/rea…

cd react-native-wx

npm i

npm run and (安卓)

npm run ios (苹果)

(上面的运转敕令,我在package.json 做了封装,一些处置惩罚编译毛病的敕令,我也已封装进去)

《RN 从上手到“摒弃”》

实行敕令后,会自动弹出nodejs 实行终端界面,这个是顺序运转的一个监控

《RN 从上手到“摒弃”》
模拟器显现:
《RN 从上手到“摒弃”》

3、分步完成

3.1 初始化并运转项目

react-native init AwesomeProject
react-native run-ios

3.2 项目构造申明

3.3 新建文件夹 app,接下来一切的源码文件代码将在这里

《RN 从上手到“摒弃”》

如今新建 component组件、page页面、及utils 东西三个,背面会依据须要建新的文件夹。

《RN 从上手到“摒弃”》
四个一级界面+ 谈天和朋友圈的界面

3.4 装置插件做页面导航跳转

3.4.1 npm install react-navigation -S

3.4.2 修正项目文件下的App.js

这是根文件,我们的页面导航写进这个组件,我项目中已完成代码片断,这里直接运用,代码以下:

import React from 'react';
import HomeScreen  from './app/page/Home'
import DiscoverScreen from './app/page/Discover'
import UserListScreen from './app/page/UserList'
import MyScreen from './app/page/My'
import CameraComponent from './app/component/camera'
import ChatScreen from './app/page/Chat'
import FriendCircle from './app/page/friendCircle'
import Icon from "react-native-vector-icons/Ionicons";
import { View, Text } from 'react-native';
import { createAppContainer, createBottomTabNavigator, createStackNavigator, createDrawerNavigator } from 'react-navigation'; // Version can be specified in package.json


const HomeNav = createStackNavigator({
  Home: {
    screen: HomeScreen,
    navigationOptions:{
      headerTitle:'微信',
      headerBackTitle:null,
    }
  },
})
const UserListNav = createStackNavigator({
  UserList: {
    screen: UserListScreen,
  },
})

// 二级页面写进一级页面中
const DiscoverNav = createStackNavigator(
  {
    Discover: {
      screen: DiscoverScreen,
    },
  }
)

const MyNav = createStackNavigator(
  {
    My: MyScreen,
  }
);

let BottomNav = createBottomTabNavigator(
  // createBottomTabNavigator 两个参数,一个页面路由,一个是路由设置
  {
    微信: HomeNav,
    通讯录: UserListNav,
    发明: DiscoverNav,
    我: MyNav,
  },
  {
    defaultNavigationOptions: ({ navigation }) => ({
      tabBarIcon: ({ focused, horizontal, tintColor }) => {
        const { routeName } = navigation.state;
        let iconName;
        let badgeCount = 3
        switch(routeName) {
          case '微信':
            iconName = 'ios-text';
            break;
          case '通讯录':
            iconName = 'md-person-add';
            break;
          case '发明':
            iconName = 'md-compass';
            break;
          case '我':
            iconName = 'ios-person';
            break;
        }
        iconColor = `${focused ? '#1AAD19' : '#4D4D4D'}`;

        return (
          <View>
            <Icon name={iconName} size={18} color={iconColor}></Icon>
            { routeName === '发明' && badgeCount > 0 && (
              <View style={{
                // If you're using react-native < 0.57 overflow outside of the parent
                // will not work on Android, see https://git.io/fhLJ8
                position: 'absolute',
                right: -6,
                top: -3,
                backgroundColor: 'red',
                borderRadius: 6,
                width: 12,
                height: 12,
                justifyContent: 'center',
                alignItems: 'center',
                color: '#fff'
              }}>
                <Text style={{ color: '#fff', fontSize: 10, fontWeight: 'bold' }}>{badgeCount}</Text>
              </View>
            )}
          </View>
        )
      },
    }),
    tabBarOptions: {
      activeTintColor: '#1AAD19',
      inactiveTintColor: '#4D4D4D',
    },
  }
);

let RootNav = createStackNavigator({
  BottomNav: {
    screen: BottomNav,
    navigationOptions: ({ navigation, screenProps }) => {
      return {
        header: null,
      };
    }
  },
  Camera: {
    screen: CameraComponent
  },
  Chat: {
    screen: ChatScreen
  },
  FriendCircle: {
    screen: FriendCircle
  }
})

export default createAppContainer(RootNav);

这里须要参考导航材料: https://reactnavigation.org/d…

文档讲的很邃晓,看看示例就晓得怎样用了,我下面讲两个注重内容,这也是在这几天的进修中碰到的troubles.

a、建立底部导航:

createBottomTabNavigator 要领,接收两个参数,一个页面路由,一个是路由设置,
直接看这个要领名字,就晓得这个是建立底部导航的要领。
–第一个参数,页面路由,这里你写若干tab, 底部就会显现几个tab 均匀分布,(不要有杠精来袭,“假如有100个tab,怎样显现?”,哪有如许的设想,你假如有100个tab,你尝尝如许排版?)

《RN 从上手到“摒弃”》

参数的key,就是底部显现的称号,value 就是这个页面 screen。页面screen能够零丁定义引入,以下:

《RN 从上手到“摒弃”》

能够像第一个DiscoverNav,以screen定义的体式格局引入,也能够简单运用,以下面的MyNav

— 第二个参数,路由设置,在这里设置,底部导航的款式、图标、foucs 状况及badge等
tabBarIcon 望文生义,设置他的图标,我这里依据navigation.state 里的routeName 来辨别页面路由,从而为他们设置差别的 icon

《RN 从上手到“摒弃”》

b、二级页面注入Stack Navigator

我们写的页面要注入我们的导航,如许才访问到,我们这里采纳的是react-navigation的 createStackNavigaor 的createStackNavigator要领,如图:

《RN 从上手到“摒弃”》

3.4.3 详细页面逻辑

这里讲两个页面,一个是静态页面,一个是挪用接口的长列表的界面。

静态页面 discoverScreen

规划体式格局: flex, 属性和web 誊写不一致,语法参考这个不完全手册: https://shenbao.github.io/ish…

点击按钮封装: RN 内里的点击要领只能绑定在它的button 组件上,供应的其他组件我们么方法直接绑定事宜,它供应了一个封装子组件能够绑定事宜的自定义按钮-Touchable 系列 (TouchableOpacity ,TouchableNativeFeedback)以下誊写能够点击的item:

《RN 从上手到“摒弃”》

注重: 上面划线的位置,这个款式(flex: 1, flexDirection: ‘row’,)要写上。有肯定的兼容题目,假如没有这个款式,在安卓上没法点击,ios上没有影响。申明在现实开辟中,我们还要处置惩罚肯定的平台差别题目,真正完成无差别的跨平台照样有些难题。

页面header:

《RN 从上手到“摒弃”》

在static 内里没方法直接挪用组件的要领,须要借助 navigation 来做一下中转,挪用setParams将要领放进navigation内里,如许在static内里就可以够运用navigation.getParams 猎取这个要领了,以下:

《RN 从上手到“摒弃”》

过渡动画

这个要领完成的是一个 动画,我们在 写web 的时刻,会用 transform transaction 如许的动画属性,RN内里也支撑如许的动画,详细语法有所差别。这里我们用一个相对定位内里的 right值 做过渡结果。
最先定义:

《RN 从上手到“摒弃”》

在点击时刻,修正这个 this.state.animateRightValue 的值,完成动画结果,
《RN 从上手到“摒弃”》

Animated有几个动画(),这里采纳了timing,他接收两个参数,一个是监听的动画值,另一个是这个值的设置,设置动画体式格局,动画时候等。

《RN 从上手到“摒弃”》

这个页面也没有庞杂的页面逻辑,基础一看就晓得怎样回事,一些语法 api 不会的话,能够上官网lou 一眼:

《RN 从上手到“摒弃”》

调接口的页面 friendCircle

这个页面挪用了一个分页接口,上拉加载更多,长列表的组件用的是RN 原生的 FlatList 组件,这个详细运用能够参考api 文档看看,

《RN 从上手到“摒弃”》

然则就个人运用以后的以为而言,这个真正要用到临盆,还得要轻微革新一下,比方loading菊花图片要改一改。
在生命周期函数componentDidMount 内里,挪用我们的接口。说道这里,我们引出了接口封装题目,用的是自带的fetch,这个fetch 底层详细我们就不斟酌怎样完成的,如今我们须要对fetch 封装一下,轻易背面在多处运用,fetch 封装以下:

let base_url = 'https://api.scampus.cn';  //服务器基础地点
// let base_url = 'http://18.10.1.115:4000';  //服务器基础地点
let token = '';   
/**
 * @param {string} url 接口地点
 * @param {string} method 要求要领:GET、POST,只能大写
 * @param {JSON} [params=''] body的要求参数,默以为空
 * @return 返回Promise
 */
const  fetchRequest = (url, method, params = '') => {
    let header = {
        "Content-Type": "application/json;charset=UTF-8",
        "accesstoken":token  //用户上岸后返回的token,某些触及用户数据的接口须要在header中加上token
    };
    if(params == ''){   //假如收集要求中带有参数
        return new Promise(function (resolve, reject) {
            fetch(base_url + url, {
                method: method,
                headers: header
            }).then((response) => response.json())
                .then((responseData) => {
                    resolve(responseData);
                })
                .catch( (err) => {
                    reject(err);
                });
        });
    } else{   //假如收集要求中没有参数
        return new Promise(function (resolve, reject) {
            fetch(base_url + url, {
                method: method,
                headers: header,
                body:JSON.stringify(params)   //body参数,一般须要转换成字符串后服务器才剖析
            }).then((response) => response.json())
                .then((responseData) => {
                    resolve(responseData);
                })
                .catch( (err) => {
                    reject(err);
                });
        });
    }
}

export default fetchRequest

运用Promise 处置惩罚异步题目,将我们末了的须要的数据一切resolve 出去。封装中规中距,基础是根据文档申明 fetch 的用法,略加修正

《RN 从上手到“摒弃”》

挪用以下:

《RN 从上手到“摒弃”》

4、运用第三方的图标

npm install -S react-native-vector-icons
图标地点: https://oblador.github.io/rea… 注重这站点不是图标悉数可用,滚动条疾速找到中心位置,就可以看到我们须要的图标。
运用: <Icon name=”ios-arrow-forward” size={18} color=”#333″ ></Icon> name 值能够在上面的地点中寻觅,哪一个适宜就用哪一个,
就个人看来,这个图标库基础够开辟运用,假如不够能够继续援用字体图标库。

5、挪用手机硬件装备-摄像头

详细演示实例,拍照功用,用的第三方库,https://github.com/react-nati…

装置: npm install -S react-native-camera
运用:import { RNCamera } from ‘react-native-camera’;

<View style={styles.container}>
    <RNCamera
        ref={ref => {
            this.camera = ref;
        }}
        style={styles.preview}
        type={ this.state.cameraType}
        flashMode={RNCamera.Constants.FlashMode.on}
        autoFocus={RNCamera.Constants.AutoFocus.on}
        androidCameraPermissionOptions={{
            title: 'Permission to use camera',
            message: 'We need your permission to use your camera',
            buttonPositive: 'Ok',
            buttonNegative: 'Cancel',
        }}
        androidRecordAudioPermissionOptions={{
            title: 'Permission to use audio recording',
            message: 'We need your permission to use your audio',
            buttonPositive: 'Ok',
            buttonNegative: 'Cancel',
        }}
        onGoogleVisionBarcodesDetected={({ barcodes }) => {
            console.log(barcodes);
        }}
    >
        {({ camera, status, recordAudioPermissionStatus }) => {
            if (status !== 'READY') return <PendingView />;
            return (
            <View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-around',marginBottom: 20 }}>
                <TouchableOpacity onPress={() => this.takePicture(camera)} style={styles.capture}>
                    <Text style={{ fontSize: 14 }}> 拍照 </Text>
                </TouchableOpacity>
                <TouchableOpacity onPress={this.swtichCamera} style={styles.capture}>
                    <Icon name="ios-reverse-camera" size={18} color="#333"></Icon>
                </TouchableOpacity>

                <TouchableOpacity onPress={this.lookAlbum} style={styles.imgPreview}>
                        <Image
                            style={styles.imgPreview}
                            source={{uri: this.state.currentUri || 'https://yyb.gtimg.com/aiplat/page/product/visionimgidy/img/demo6-16a47e5d31.jpg?', isStatic: true}}
                        />
                    </TouchableOpacity>
                    
                </View>
                );
            }}
        </RNCamera>
    </View>

在组件内里能够定义拍照机界面的ui,能够自定义拍照按钮,切换摄像头的按钮,拍照图片预览等,挪用api 不难,题目难点在设置挪用的文件,你得有权限挪用原生的装备。
1、修正android/gradle/wrapper/gradle-wrapper.properties

distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip

2、修正android/app/build.gradle

missingDimensionStrategy 'react-native-camera', 'general'

《RN 从上手到“摒弃”》

在现实装置运用的时刻会有相干的提醒报错,根据报错信息去寻觅处理方法,这里照样得引荐github,上面有许多相似的题目,能够耐烦找找。

6、结言

从一最先相识RN 到末了上手demo,到如今连续修正项目,差不多十天时候,本人的手艺栈是vue,react 并没有临盆项目,看看文档,基础能够上手。总结而言,运用一些基础的功用,并不难,文档很全,运用的群体很大,所以碰到的题目也能够在相干社区找到适宜的处理要领或许替代计划。还没有详细开辟临盆项目,然则我以为我将要面对的题目,应该在体验优化上,比方过渡动画,上拉下拉革新加载,切换视图;集成第三方库,挪用硬件装备;机能优化题目等。

7、TODO

背面有时候,继续把这个项目做下去,

  • 登录注册
  • 谈天,背面集成谈天机器人
  • 通讯录的职员分组,如今由于是背景接口还没有完成,只是当地造了一个数据
  • 扫码功用
  • 发动态
  • 集成舆图
  • 拍照后,图像识别

假如有兴致的同砚迎接到场一同完成。
react-native 的地点:https://github.com/adouwt/rea…
nodejs的背景地点: https://github.com/adouwt/nod…

-1、相干毛病处置惩罚

  • react-native-camera 插件的运用题目:

《RN 从上手到“摒弃”》

处理: https://github.com/react-native-community/react-native-camera/issues/2150

  • 编译题目

《RN 从上手到“摒弃”》

    处理: cd android   &&  ./gradlew clean
  • Unable to resolve module ‘scheduler/tracing’ in ReactNative

    处理: yarn add @babel/runtime@7.0.0 再从新跑 react-native run-android

  • 继续百度舆图 ios 打包题目

https://github.com/devdawei/l…

https://blog.csdn.net/weixin_…

https://www.jianshu.com/p/ece…

开辟中还碰到了其他题目,然则忘了做纪录 ~~ RN 临时“摒弃”,接下来要运用 flutter,盘算两周后 出一个flutter版本。

–2019-6-4 更新
近来抽闲在撸 flutter的版本:
github: flutter_wx 有兴致的同砚,能够先点进去看看,背面后抽闲迭代开辟。

    原文作者:adouwt
    原文地址: https://segmentfault.com/a/1190000019333809
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞