React Native介紹
React Native 是Facebook開源的一個跨平臺移動應(yīng)用開發(fā)框架。直白點(diǎn)說,借助React Native你可以直接使用JS來開發(fā)原生移動應(yīng)用。
React和React Native
React也是Facebook開源的一個框架,一個JS UI 框架,React Native 是以React為一部分基礎(chǔ)的衍生產(chǎn)品。也就是說,除了JavaScript,你還需要熟悉一下React這個UI框架,以便于更好的上手React Native。
安裝
使用React Native開發(fā)原生APP時,除了JS的Node環(huán)境,還是需要配置好相關(guān)的原生開發(fā)環(huán)境。Android的JDK和Android Studio,IOS的XCODE,當(dāng)然一般還會裝一些輔助的工具,這里就不詳細(xì)說明了,React Native中文網(wǎng)上有詳細(xì)的開發(fā)環(huán)境搭建說明文檔。
- RN中文網(wǎng) http://reactnative.cn/
- RN官網(wǎng) https://facebook.github.io/react-native/
- 我自己的簡書博客 http://www.lxweimin.com/p/138807f257e7
第一個RN應(yīng)用
搭建好開發(fā)環(huán)境后,我們就可以使用RN開發(fā)原生APP了。在cmd中鍵入下列命令就可以生成一個RN的helloworld項目,并在android機(jī)器上運(yùn)行起來
react-native init AwesomeProject
cd AwesomeProject
react-native run-android
運(yùn)行起來后就是下面的界面
可以看到界面中也給了我們相應(yīng)的提示,打開工程根目錄中的
App.js
文件
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View
} from 'react-native';
const instructions = Platform.select({
ios: 'Press Cmd+R to reload,\n' +
'Cmd+D or shake for dev menu',
android: 'Double tap R on your keyboard to reload,\n' +
'Shake or press menu button for dev menu',
});
export default class App extends Component<{}> {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit App.js
</Text>
<Text style={styles.instructions}>
{instructions}
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
修改render()方法中的返回
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Hello React Native!
</Text>
</View>
);
}
然后選中模擬器雙擊鍵盤R
,就更新界面了。
我們還可以使用
Ctrl+M
呼出開發(fā)者菜單,真機(jī)的話,搖一搖即可。上圖的菜單先簡單介紹幾個,
Reload
就是加載資源即為刷新,Enable Hot Reload
為熱加載,開啟此選項,開發(fā)時代碼變動,界面自動刷新。以后除非原生代碼改動,可以使用npm start
快速開啟調(diào)試服務(wù),不需要每次都運(yùn)行react-native run-android
然后再回過頭看下
App.js
的代碼,可以發(fā)現(xiàn)React Native基本跟React是差不多的,只不過基礎(chǔ)組件不是web組件而是原生組件。這里先列出RN的基礎(chǔ)組件
- AccessibilityInfo
- ActivityIndicator
- Button
- CheckBox
- DatePickerIOS
- DrawerLayoutAndroid
- FlatList
- Image
- KeyboardAvoidingView
- ListView
- ListView.DataSource
- Modal
- NavigatorIOS
- Picker
- PickerIOS
- ProgressBarAndroid
- ProgressViewIOS
- RefreshControl
- ScrollView
- SectionList
- SegmentedControlIOS
- Slider
- StatusBar
- Switch
- TabBarIOS
- TabBarIOS.Item
- Text
- TextInput
- ToolbarAndroid
- TouchableHighlight
- TouchableNativeFeedback
- TouchableOpacity
- TouchableWithoutFeedback
- View
- ViewPagerAndroid
- VirtualizedList
- WebView
使用基礎(chǔ)組件時先從react-native
包中導(dǎo)入,比如我們使用Button
時,先添加導(dǎo)入
import {
Button
} from 'react-native';
然后在reder方法中返回
render() {
return (
<View style={styles.container}>
<Button title={'hello rn'} onPress={()=>{
alert('hello rn')
}}/>
</View>
);
}
各組件的使用可以閱讀官方或中文網(wǎng)文檔,有詳細(xì)介紹。這里補(bǔ)充一些React的相關(guān)知識。前面的代碼就有兩個React的基礎(chǔ)概念,Component組件和JSX語法,Component組件是React中很重要的一個概念,React組件使用render方法接收數(shù)據(jù)并輸出JSX展示。上面代碼中類似xml的寫法就稱為JSX,是react對js的一種語法擴(kuò)展。JSX與xml語法類似,可以定義屬性和子元素,不同的是通過{}
來加入js表達(dá)式。接觸過angular
或vue
的同學(xué)應(yīng)該對這種寫法會比較熟悉。再說明一點(diǎn),JSX也是一種表達(dá)式,在編譯以后也會轉(zhuǎn)換成普通的js對象。也就說你可以像下面這么用
let text = <Text>hello rn</Text>
if(isAndroid)
{
return <Text>hello android</Text>
}else
{
return <Text>hello ios</Text>
}
let txts = [];
txts.push(<Text>hello rn</Text>);
關(guān)于Component組件還有兩個重要概念,props
(屬性)和state
(狀態(tài)),在組件內(nèi)我們通過props
來訪問傳入的數(shù)據(jù),比如說我們之前使用的button
組件
<Button title={'hello rn'}/>
在Button
類中,就可以通過props
訪問到
class MyButton extends Component{
render ()
{
let title =this.props.title
...
}
}
而state
是用來保持組件內(nèi)部狀態(tài)的,當(dāng)state
改變時,組件會重新調(diào)用render()
方法,刷新組件UI。
class MyButton extends Component{
constructor(props){
super(props);
this.state={
title:props.title
}
}
onClick(){
this.setState({title:'isClicked'})
}
}
在constructor()
構(gòu)造方法中賦值,使用this.setState()
方法更新state
。
布局和樣式
所有的基礎(chǔ)組件都接收一個style
屬性,接收一個對象或數(shù)組,組件的寬高背景等等都是通過這個屬性來定制的
<View style={{
height:100,
width:100,
backgroundColor:'red'
}}>
...
</View>
使用的樣式名基本都遵循了web上的css命名,只是按照J(rèn)S的語法規(guī)范使用了駝峰命名法,列如background-color
改為backgroundColor
,而且給寬高設(shè)置的尺寸都是沒有單位的,表示與設(shè)備像素?zé)o關(guān)的邏輯像素點(diǎn)。補(bǔ)充說明一下單位轉(zhuǎn)換和尺寸適配的問題,單位方面,一般現(xiàn)在UI會給我們PxCook的源文件,Android的話,對照相應(yīng)密度的dp大小設(shè)置即可。IOS,對照相應(yīng)倍圖的pt大小設(shè)置即可。屏幕尺寸方面,因為布局采用的是flexBox,所以對不同的屏幕尺寸基本上能提供一致的布局結(jié)構(gòu)。其他更細(xì)節(jié)的適配需求,現(xiàn)在并沒有系統(tǒng)整理,以后再和大家分享交流。
然后再說下FlexBox布局,RN中的FlexBox布局和Web上的CSS基本一致,但有兩點(diǎn)差異,flexDirection
的默認(rèn)值是column而不是row,而flex也只能指定一個數(shù)字值。在平常開發(fā)的時候,使用flexDirection
、alignItems
和 justifyContent
三個樣式屬性就已經(jīng)能滿足大多數(shù)布局需求,使用flexDirection
決定布局的主軸,justifyContent
決定子元素在主軸上的位置,alignItems
決定子元素在次軸上的位置。舉個栗子吧,這樣比較形象一點(diǎn),比如下圖所示的界面
圖中卡片布局的大致實(shí)現(xiàn)代碼如下
<View style={{alignItems:'center',justifyContent:'center',minHeight:100...}}>
<Text style={{color:'white'...}}>
昨日票房 2017年11月7日
</Text>
<View style={{flexDirection:'row',alignItems:'center',marginTop:20...}>
<Text style={{color:'white',fontSize:24...}}>
701786
</Text>
<Text style={{color:'white',marginTop:10}}>
萬
</Text>
</View>
<Text style={{color:'white',,marginTop:20...}}>
每日0點(diǎn)更新票房
</Text>
</View>
上面的代碼只是大概布局思路,當(dāng)然這個卡片的真正實(shí)現(xiàn)還用到了LinearGradient
控件和ImageBackground
控件。
頁面跳轉(zhuǎn)
我們一般使用React Navigation
來構(gòu)建多頁面以及跳轉(zhuǎn)頁面,使用前要先安裝
yarn add react-navigation
然后在app.js
(如果你沒改動index.js
中的app組件注冊的話)注冊頁面
import { StackNavigator } from 'react-navigation';
import Main from "./pages/main";
import NationwideDetail from "./pages/cinema/nationwideDetail";
import Cinema from "./pages/cinema/cinemaIndex";
import DatePickerPage from "./pages/common/datePickerPage";
import ForecastDetail from "./pages/cinema/forecastDetail";
import CinemaDetail from "./pages/cinema/cinemaDetail";
const RootNavigator = StackNavigator({
NationwideDetail:{
screen:NationwideDetail,
},
Cinema:{
screen:Cinema
},
DatePickerPage:{
screen:DatePickerPage
},
ForecastDetail:{
screen:ForecastDetail
},
CinemaDetail:{
screen:CinemaDetail
}
});
export default RootNavigator;
最初顯示第一個注冊頁面,注冊完成之后,每個頁面中的props
屬性可以獲得navigation
對象,通過navigation
對象進(jìn)行頁面跳轉(zhuǎn)
this.props.navigation.navigate('NationwideDetail')
也可以攜帶參數(shù)
this.props.navigation.navigate('NationwideDetail',{name:'wuHuaRong'})
參數(shù)在navigation.state.params.name
中獲取。
返回頁面
我們還可以通過navigation.goBack()
方法關(guān)閉當(dāng)前頁面返回上個頁面,navigation.goBack('NationwideDetail')
可以指定回到某個頁面。如果還想關(guān)閉頁面時返回某個值,類似android中的startActivityForResult
,需要再集成redux
狀態(tài)機(jī)來管理多個頁面之間的共享狀態(tài)。此部分,先不詳細(xì)說明了。
網(wǎng)絡(luò)請求
RN提供了與web一致的Fetch API,也允許使用XMLHttpRequest API,以及基于XMLHttpRequest的第三方庫frisbee或是axios,此部分文檔有詳細(xì)說明就不再贅訴了。
觸摸
簡單的點(diǎn)擊和長按事件可以使用官方提供的四個Touchable
控件,TouchableHighlight
、TouchableNativeFeedback
、TouchableOpacity
、TouchableWithoutFeedback
<TouchableHighlight onPress={this._onPressButton} onLongPress={this._onLongPressButton}>
<Text>Button</Text>
</TouchableHighlight>
上下左右滑動可以使用ScrollView
組件,復(fù)雜的手勢請參考PanResponder
API
異步問題
因為RN中只有一個JS執(zhí)行線程,是不能直接開啟一個異步線程的來執(zhí)行耗時操作的,但是可以使用InteractionManager
來保障UI的渲染性能的。
InteractionManager.runAfterInteractions(() => {
// ...需要長時間同步執(zhí)行的任務(wù)...
});
資源引用
使用require
方法來引用項目中的靜態(tài)資源,如.png
,.mp3
,.wav
,mp4
,.mov
,.html
和.pdf
等
比如Image
控件的使用
<Image source={require('./my-icon.png')} />