React Native入门指南(上)

image

前言

Learn once, write anywhere: Build mobile apps with React

FacebookReact.js Conf 2015年会议上发布了React Native(以下简称RN )。RN 是一个使用React构建Native App的框架,支持Android 4.1+iOS 8+平台。它充分利用了Facebook现有的轮子,成为前端和客户端技术的集大成者。
RN兼备H5的动态性和Native的性能,完美弥补了手机浏览器性能和Native硬编码的弊端。

RN 的前身是React,这是一个为了解决项目越来越复杂导致DOM频繁操作和界面重绘,而诞生的高性能渲染框架。
它只描述了View层,Facebook 2014年发布Flux,以及Redux等模式框架和React配套使用。

RN 社区活跃度非常高,有完善的文档和众多贡献者支持,不用担心没资料而苦恼,这是RN 能从同类框架(主要指Weex)脱颖而出的优势之一。但是也侧面反映了RN 还不稳定,至今依然没有发布1.0版本。目前RN每两周会发布一个小版本,并提供了完善的升级支持。

在正式开始阅读文章之前,希望你具备以下知识:
- JavaScript 基本知识
- 对 Android 或 iOS 平台开发有了解

ES6 语法基础

RN 目前采用ES6作为其编程语法标准,ES6全称ECMAScript 6.0JavaScript语言的下一代标准,在2015年6月正式发布。它的目标是使JavaScript可以用来编写复杂的大型应用程序,成为企业级开发语言。ECMAScriptJavaScript的关系是,前者是后者的规范,后者是前者的一种实现。

这一章使用最简单的语法带你快速了解ES6,帮助你能理解和阅读RN的代码。如果你很了解ES6请跳过这章节。
想要了解更多,推荐阮一峰的ECMAScript 6 入门

变量的定义

除了常用的var命令和function命令,E6还支持let,const命令

1. let

{
  let a = 10;
  var b = 1;
}

let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。

2. 块作用域

function f1() {
  let n = 5;
  if (true) {
    let n = 10;
  }
  console.log(n); // 5
}

上面两个代码块都声明了变量n,运行后输出5。这表示外层代码块不受内层代码块的影响。

{{{{{let insane = 'Hello World'}}}}};

ES6 允许块级作用域的任意嵌套

3. const

const PI = 3.1415;

const声明一个只读的常量。一旦声明,常量的值就不能改变。

函数的定义

1. 指定函数默认值

function log(x, y = 'World') {
  console.log(x, y);
}

log('Hello') // Hello World
log('Hello', 'World') // Hello World
log('Hello', '') // Hello

2. 箭头函数

var f = v => v;

等同于

var f = function(v) {
  return v;
};
// 正常函数写法
[1,2,3].map(function (x) {
  return x * x;
});

// 箭头函数写法
[1,2,3].map(x => x * x);

简化回调函数

Class 的基本语法

1. 定义类

class Foo {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
}

var foo = new Foo();
foo.toString();

上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。

const MyClass = class Foo {
  getClassName() {
    return Me.name;
  }
};

与函数一样,类也可以使用表达式的形式定义。
ES6不提供私有方法和属性的支持,常用在方法名前加_的方式进行区分,如_methodName()

2. 定义实例属性

class Foo {
  state = {
    count: 0
  };
}

3. 定义静态方法和属性

class Foo {
  static classMethod() {
    return 'hello';
  }
}

Foo.prop = 1;
Foo.classMethod() // 'hello'

上面代码使用static定义了一个静态方法,表示该方法不会被实例继承,而是直接通过类来调用。
Foo.prop = 1;表示定义了Foo类的一个静态属性。

Module 的语法

历史上,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。

1. CommonJS

let { stat, exists, readFile } = require('fs');

上面代码的实质是整体加载fs模块(即加载fs的所有方法),生成一个对象(_fs),然后再从这个对象上面读取3个方法。这种加载称为“运行时加载”。

2. export和import命令

export命令用于规定模块的对外接口
import命令用于输入其他模块提供的功能

//将变量声明为外部可用
//方法1
export var firstName = 'Michael';

//方法2
var lastName = 'Jackson';
export {lastName};

//将函数声明为外部可用
export function multiply(x, y) {
  return x * y;
};

//将类声明为外部可用
export class { ... }

//加载模块
import {firstName, lastName} from './profile';

import后面的from指定模块文件的位置,可以是相对路径,也可以是绝对路径
注意,import命令具有提升效果,会提升到整个模块的头部,首先执行。

3. export default 命令

// export-default.js
export default function () {
  console.log('foo');
}

// import-default.js
import customName from './export-default';
customName(); // 'foo'

使用import命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载,为了给用户提供方便,要用到export default命令,为模块指定默认输出。这时候customName为任意名字都可进行调用。

组件

组件与生命周期

import React, { Component } from 'react';
import { AppRegistry, Text } from 'react-native';

export default class ReactSample extends Component {
  render() {
    return (
      <Text>Hello ReactNative!</Text>
    );
  }
}

AppRegistry.registerComponent('ReactSample', () => ReactSample);

上面的代码定义了一个名为ReactSampleComponent
- ReactSample类的render()方法告诉当前组件要绘制的View;
- AppRegistry.registerComponent()方法告知RN哪一个组件被注册为整个应用的根容器;
- 常用的组件有<Button> <FlatList> <Image> <Text> <TextInput> <View>等等。

Props

设置组件的Props进行定制

<Image source={{uri: url}} style={{width: 193, height: 110}} />
<Text numberOfLines={1} style={{fontSize: 20}}>Hello ReactNative</Text>

sourcestyleImage 组件的Props
numberOfLinesstyleText组件的Props
当然实际的属性远不止这些。

State

props是在父组件中指定,一经指定,在被指定的组件的生命周期中则不再改变。 对于需要改变的数据,我们需要使用state。

 constructor() {
    super();
    this.state = { 
        loaded: false 
    };
  }

上面代码,我们在构造函数中为state添加了一个属性loaded表示数据加载的状态。
当数据加载完成后通过以下代码设置改变状态的属性:

 this.setState({
    loaded: true
 });

样式

在 RN 中,你并不需要学习新语法来定义样式。我们仍然像写CSS一样编写我们的样式,这些属性名基本上遵循了CSS的命名,只是改成了驼峰命名法。例如将background-color改为backgroundColor。所有的核心组件都接受名为style的属性。

const styles = StyleSheet.create({

    rowTitle: {
        marginLeft: 10,
        marginRight: 10,
        fontSize: 16,
    }
});

//使用styles
<Text style={styles.rowTitle}>Hello ReactNative</Text>

手势响应

RN 提供了一组抽象的Touchable实现,用来做“可触控”的组件。这一实现利用了响应系统,使得你可以简单地以声明的方式来配置触控处理。想了解更多手势响应,多指操作实现,请参考Gesture Responder System

<TouchableOpacity onPress={() => Alert.alert("click")}>
    <Text >Click..</Text>
</TouchableOpacity>

<TouchableHighlight onPress={() => Alert.alert("click") underlayColor={'#999999'}>
    <Text >Click..</Text>
</TouchableHighlight>

<TouchableNativeFeedback onPress={...} background={TouchableNativeFeedback.Ripple('#333333', false)}>
    <Text >Click..</Text>
</TouchableNativeFeedback>

TouchableHighlightTouchableOpacity区别仅仅是多了些属性,例如设置underlayColor,它表示点击时显示出来底层的颜色。

TouchableNativeFeedback看起来更高级一些,他可以通过background属性,设置Android主题中的触摸样式,如涟漪效果。
推荐使用以下静态方法快速指定background
- TouchableNativeFeedback.SelectableBackground() : Android主题默认的按下背景效果。
- TouchableNativeFeedback.SelectableBackgroundBorderless()Android主题默认的按下背景效果(无边框)。
- TouableNativeFeedback.Ripple(color, borderless) :涟漪效果,可以指定颜色和边界。

<TouchableWithoutFeedback onLongPress ={...}}>
    <Text >onLongPress..</Text>
<TouchableWithoutFeedback/>

并不推荐使用TouchableWithoutFeedback,和其他Touchable系列相比,没有视觉反馈,多了很多额外的事件属性,如onLongPressonPressOut等。

生命周期

提到生命周期,无非是创建、更新、销毁。RN 的组件就是一个状态机,它接收两个输入参数:propsstate,返回一个Virtual DOM。换句话说组件的状态变化取决于propsstate,和原生一样,RN也为我们提供相应的回调函数。

  • componentWillMount : 准备渲染组件前(第一次调用reader()之前)调用。
  • render : 渲染界面,务必实现的方法。
  • componentDidMount :组件第一次渲染之后调用。
  • componentWillUnmount : 当组件要被从界面上移除的时候调用。
  • componentWillReceiveProps :当组件收到新的属性(props),就会触发该方法。
  • shouldComponentUpdate:当组件收到新的属性和状态改变时,就会触发该方法。
  • componentWillUpdateshouldComponentUpdate返回true之后,准备更新组件界面之前。
  • componentDidUpdate : 组件更新完界面(调用reader())之后。

简单看一下组件的生命周期,记住reader是必须实现的你就可以继续往下阅读了。

Flexbox布局

RN中的Flexbox工作原理和Web上CSS Flexbx布局方式基本一致,当然也存在少许差异。比如默认值不同:flexDirection的默认值是column而不是row。

元素

采用Flex布局的元素,称为flex container,简称"容器"。它的所有子元素自动成为容器成员,称为flex item,简称"项目"。

image

容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end
项目默认沿主轴排列。单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size

上面这张图是Flex布局的精髓,看懂了就会用了,下面的属性介绍就可以当参考资料了~

容器的属性

flexDirection :容器主轴排列方向

box: {
    flexDirection: row | row-reverse | column | column-reverse
}
  • row : 从左端开始,水平(横)方向。
  • row-reverse : 从右端开始,水平(横)方向。
  • column : 默认值,从上方开始,垂(纵)直方向。
  • column-reverse : 从下方开始,垂(纵)直方向。

flexWrap:默认情况下Item都排到一条线上,该属性定义换行方式。

box: {
    flexWrapp: nowrap | wrap | wrap-reverse
}
  • nowrap : 不换行。
  • wrap : 换行,第一行在上面。
  • wrap-reverse : 换行,第一行在下面。

flexFlow:flexDirectionflexWrap的复合属性

box: {
  flexFlow: <flex-direction> || <flex-wrap>
}

justifyContent:定义了Item在主轴上的对齐方式

box: {
    justifyContent: flex-start | flex-end | center | space-between | space-around;
}
  • flex-start:左对齐。
  • flex-end:右对齐。
  • center: 居中。
  • space-between:两端对齐,Item间隔相等。
  • space-around:Item与边框两侧间隔相等,Item之间间隔比Item与边框间隔大一倍。

alignItems:交叉轴的对齐方式

box: {
    alignItems: flex-start | flex-end | center | baseline | stretch;
}
  • flex-start:起点对齐。
  • flex-end:终点对齐。
  • center:居中对齐。
  • baseline: Item第一行文字基线对齐。
  • stretch:如果Item未设置高度或设为auto,将占满整个容器的高度。

alignContent:定义了多根轴线的对齐方式。如果Item只有一根轴线,该属性无效

box: {
    alignContentt: flex-start | flex-end | center | space-between | space-around | stretch;
}
  • flex-start:起点对齐。
  • flex-end:终点对齐。
  • center:居中对齐。
  • space-between:两端对齐,轴线之间的间隔平均分布。
  • space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
  • stretch:轴线占满整个交叉轴。

Item属性

  • order:Item的排列顺序,数值小的在前。
  • flexGrow:Item的放大比例。如果存在剩余空间,根据数值进行放大。
  • flexShrink:Item的缩小比例。如果空间不足,根据数值缩小。
  • flexBasis:在分配多余空间之前,项目占据的主轴空间固定大小。
  • flex:flexGrowflexShrinkflexBasis的复合属性。
  • alignSelf:允许单个Item有与其他Item不一样的对齐方式。

案例

rowCell(rowData) {
    return (
        <View style={styles.container}>
            <Image style={styles.rowHead} source={{uri: 'https://xxx.jpg'}}/>
            <Text style={styles.rowTitle}>Hello ReactNative~</Text>
        </View>
    );
}
const styles = StyleSheet.create({
    rowHead: {
        height: 40,
        width: 40,
        borderRadius: 50
    },
    rowTitle: {
        marginLeft: 10,
        marginRight: 10,
        fontSize: 16,
    },
    container: {
        margin: 10,
        alignItems: 'center',
        justifyContent: 'flex-start',
        flexDirection: 'row'
    }
}

上面的代码很简单,定义了一个其Item水平排列,起点对齐其的container,包含<Text><Image>两个元素。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

返回主页看更多
狠狠的抽打博主 支付宝 扫一扫