傳統的單頁面應用,基於url的hash值進行路由跳轉,hybrid App的跳轉原理與此不同,其原理更像是web瀏覽器的前進後退。
在 web 瀏覽器中,使用<a>標籤作爲錨點,鏈接到不同的頁面。 當用戶單擊某個鏈接時, 該 URL 就會被推送到瀏覽器歷史記錄堆棧。 瀏覽器通過兩個棧實現前進後退。一個棧X,一個棧Y。每次跳轉到新頁面時將此頁面壓入X,並清空Y;當點擊後退按鈕式時,將X出棧,並壓入到Y;當點擊前進按鈕時,將Y出棧,壓入X。X爲空時表示沒有頁面可以後退瀏覽了,當Y爲空時表示沒有頁面可以前進瀏覽了。
React Navigation是RN官方提供的工具,它有三種導航方式:
Stack navigation:頂部導航條,用來跳轉頁面和傳遞參數
Tab navigation:底部標籤欄,用來區分模塊
Drawer navigation:抽屜,從App左側滑出一個頁面
stack navigation類似瀏覽器的導航處理,本文我們討論的就是stack navigation方式。 當用戶與它進行交互時,應用程序會從導航堆棧中新增和刪除頁面,這樣就實現了不同頁面的切換。
下面是我學習過程對官方文檔的一個個人總結。
官方文檔:React Navigation
插件安裝
npm install react-navigation --save
npm install react-native-gesture-handler
最簡單的實現一般包括以下幾個步驟
1、定義路由
使用createStackNavigator方法,該方法返回 React 組件。
import {createStackNavigator} from 'react-navigation';
import Main from '../Main';
import Page1 from '../Page1';
import Page2 from '../Page2';
export const Router = createStackNavigator({
Main: {screen: Main}, // routeName: {screen: component}
Page1: {screen: Page1},
Page2: {screen: Page2},
}
);
你可以將此文件直接寫在App.js中,或者單獨寫一個文件,再在App.js中引用。我這裏單獨寫成一個文件。
注意需要用AppContainer包裹整個環境。
App.js
import React, { Component } from 'react';
import { createAppContainer } from "react-navigation";
import {Router} from './src/navigator/Router';
const AppContainer = createAppContainer(Router);
export default class App extends Component {
render() {
return <AppContainer />;
}
}
2、實現跳轉
定義好路由之後,調用this.props.navigation.navigate('Page1')方法實現跳轉。
這裏還有另一個方法this.props.navigation.push('Page1'),它與navigate()方法的區別是,如果從當前頁跳轉到當前頁(比如我們複用組件,只是改變裏面的某些參數),調用 navigate(),它不會做任何改變,push()方法則不考慮現有導航,直接添加路由,所以可以實現當前頁到當前頁的跳轉。
返回上一頁,用this.props.navigation.goBack()方法。
3、數據傳遞
this.props.navigation.navigate('RouteName', yourParam)
讀取數據:this.props.navigation.state.params。讀取數據還可以用this.props.navigation.getParam('itemId', 'defaultValue'),這種方式,因爲我們已經設置了一個default value,所以不必處理參數爲空的情況。
修改當前頁的參數:this.props.navigation.setParam ({otherParam: 'Updated!'})。
4、配置標題欄
單個組件標題欄
通過配置navigationOptions實現自定義標題欄。
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
};
/* render function, etc */
}
設置通用標題欄樣式
上述方法是在單個頁面中設置標題欄的方法,如果我們要爲所有頁面的header設置統一的樣式,無需在每個頁面中寫重複的代碼,在createStackNavigator配置defaultNavigationOptions即可。
export const Router = createStackNavigator({
Main: {screen: Main}, // routeName: {screen: component}
Page1: {screen: Page1},
Page2: {screen: Page2},
},
{
initialRouteName: 'Main', // 初始化加載的頁面
defaultNavigationOptions: { // 設置統一的header樣式
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
},
}
);
標題欄傳值
注意navigation的引用方式
class DetailsScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
title: navigation.getParam('otherParam', 'A Nested Details Screen'),
};
};
/* render function, etc */
}
使用自定義組件替換標題欄
class LogoTitle extends React.Component {
render() {
return (
<Image
source={require('./spiro.png')}
style={{ width: 30, height: 30 }}
/>
);
}
}
class HomeScreen extends React.Component {
static navigationOptions = {
// headerTitle instead of title
headerTitle: <LogoTitle />,
};
/* render function, etc */
}
5、爲標題欄添加按鈕
static navigationOptions = {
headerTitle: <LogoTitle />,
headerRight: (
<Button
onPress={() => alert('This is a button!')}
title="Info"
color="#fff"
/>
),
};