開始今天的話題以前,讓咱們先來了解一下前端路由,Ajax誕生之後,解決了每次用戶操做都要向服務器端發起請求重刷整個頁面的問題,但隨之而來的問題是沒法保存Ajax操做狀態,瀏覽器的前進後退功能也不可用,當下流行的兩種解決方法是:前端
爲了讓history不只僅能回退到上一個頁面,還能夠回到上一個操做狀態。HTML5新增了三個方法,其中兩個是在history對象裏的:react
window.onpopstate() 監聽url的變化,會忽略hash的變化(hash變化有一個onhashchange事件),可是前面的兩個事件不會觸發它。android
總結:git
單頁面應用或者Ajax操做記錄狀態用的就是hash和h5增長的history API,這就是react-router-dom 擴展的路由實現,也是web應用最經常使用的兩種路由github
//引入必要的資源包 import ReactDom from 'react-dom'; import { Router, Route, hashHistory,IndexRoute} from 'react-router'; //路由頁面配置 ReactDom.render( <Router history={hashHistory}> <Route path='/' component={Page}></Route> <Route path='/NewTask' component={NewTask} /> <Route path='/Redeem' component={Redeem} /> <Route path='/Rule' component={Rule} /> </Router> ,document.getElementById("app"));
當啓動react項目時,會先生成好一個路由表,發生頁面跳轉時,react會根據地址到路由表中找到對應的處理頁面或處理方法web
而動態路由不是做爲一個項目運行的配置文件存儲在外部,它在項目render的時候纔開始定義,router的做者認爲route應當和其它普通組件同樣,它的做用不是提供路由配置,而是一個普通的UI組件npm
import React, { Component } from 'react'; import { Provider } from 'react-redux'; import { StatusBarIOS,Platform } from 'react-native'; import { createMemoryHistory, Router, IndexRoute, Route } from 'react-router'; import { createNavigatorRouter } from 'react-native-navigator-router'; <Provider store={store}> <Router history={createMemoryHistory('/')}> <Route path='/' component={createNavigatorRouter()}> <IndexRoute component={App} /> <Route path="/about" component={AllRoute} /> </Route> </Router> </Provider>
因 React Native 版本設計到0.44以後,原先的 RN 路由徹底失效了redux
運行直接報錯,createMemoryHistory('/') 異常react-native
具體緣由仍是不太明白,應該是移除了react-router的使用方式,目前數組
首先從原理上,Navigator是用來做爲組件之間的導航器。而缺少相似Router性質的東西時,最簡單的辦法是將下個組件(也叫場景Scene),直接告訴導航器。因此就須要在頁面的上面引入下個組件
export default class SampleComponent extends React.Component { render() { let defaultName = 'FirstPageComponent';// 第一個要展現的組件 let defaultComponent = FirstPageComponent; return ( <Navigator initialRoute={{ name: defaultName, component: defaultComponent }} configureScene={(route) => { return Navigator.SceneConfigs.VerticalDownSwipeJump; }} renderScene={(route, navigator) => { let Component = route.component; return <Component {...route.params} navigator={navigator} /> }} /> ); } }
initialRoute={{ name: defaultName, component: defaultComponent }}
Navigator實現跳轉,是經過Push和Pop方法,至關因而一個數組,每要跳到下個Scene(場景),就把下個頁面push到這個數組中,當想要後退的時候,再把這個Pop出去
react-native 0.44 開始 再也不支持 Navigatior
NavigatorIOS使用
首先,建立一個 Home 組件,用來做爲 NavigatorIOS 的根視圖
視圖部分:
render() { return ( <ScrollView style={styles.flex}> <View style={styles.container}> <Text onPress={this.goTo.bind(this)}>點我跳轉詳情</Text> </View> </ScrollView> ); }
樣式部分:
const styles = StyleSheet.create({ flex: { flex: 1, marginTop: 65 }, listItem: { height: 40, marginLeft: 10, marginRight: 10, borderBottomWidth: 1, borderBottomColor: "#ddd", justifyContent: "center" }, listItemFont: { fontSize: 16 }, container: { justifyContent: "center", alignItems: "center" } });
而後咱們實例化一個 NavigatorIOS 並設置路由
class Test extends Component { render() { return ( <NavigatorIOS style={{ flex: 1 }} initialRoute={{ component: List,// 要跳轉的頁面 title: "列表",// 跳轉頁面導航欄標題 passProps: {} }} /> ); } }
return ( <View style={styles.container}> <TouchableOpacity onPress={() => {this.props.navigator.push({ component:Detail, // 須要跳轉的頁面 title:'詳情' // 跳轉頁面導航欄標題 rightButtonTitle: "收藏",//跳轉頁面導航右側按鈕 onRightButtonPress: function() {//右側按鈕點擊回調事件 alert("點擊了收藏按鈕。"); } })}} > <Text>點擊跳轉頁面</Text> </TouchableOpacity> </View> );
因爲前面介紹的幾種路由方式要麼隨着RN版本更新已再也不支持,要麼是單平臺支持性;RN官方在0.44版本之後把導航路由集中到了react-navigation庫裏面,而且官方也事件使用react-navigation,少用第三方插件
添加react-navigation
該庫包含三類組件:
npm install --save react-navigation
方法引用:
import { StackNavigator } from "react-navigation";
組件採用堆棧式的頁面導航來實現各個界面跳轉。它的構造函數:
StackNavigator(RouteConfigs, StackNavigatorConfig) RouteConfigs:頁面路由配置 StackNavigatorConfig:路由參數配置
navigationOptions:配置StackNavigator的一些屬性。 title:標題,若是設置了這個導航欄和標籤欄的title就會變成同樣的,不推薦使用 header:能夠設置一些導航的屬性,若是隱藏頂部導航欄只要將這個屬性設置爲null headerTitle:設置導航欄標題,推薦 headerBackTitle:設置跳轉頁面左側返回箭頭後面的文字,默認是上一個頁面的標題。能夠自定義,也能夠設置爲null headerTruncatedBackTitle:設置當上個頁面標題不符合返回箭頭後的文字時,默認改爲"返回" headerRight:設置導航條右側。能夠是按鈕或者其餘視圖控件 headerLeft:設置導航條左側。能夠是按鈕或者其餘視圖控件 headerStyle:設置導航條的樣式。背景色,寬高等 headerTitleStyle:設置導航欄文字樣式 headerBackTitleStyle:設置導航欄‘返回’文字樣式 headerTintColor:設置導航欄顏色 headerPressColorAndroid:安卓獨有的設置顏色紋理,須要安卓版本大於5.0 gesturesEnabled:是否支持滑動返回手勢,iOS默認支持,安卓默認關閉 screen:對應界面名稱,須要填入import以後的頁面 mode:定義跳轉風格 card:使用iOS和安卓默認的風格 modal:iOS獨有的使屏幕從底部畫出。相似iOS的present效果 headerMode:返回上級頁面時動畫效果 float:iOS默認的效果 screen:滑動過程當中,整個頁面都會返回 none:無動畫 cardStyle:自定義設置跳轉效果 transitionConfig: 自定義設置滑動返回的配置 onTransitionStart:當轉換動畫即將開始時被調用的功能 onTransitionEnd:當轉換動畫完成,將被調用的功能 path:路由中設置的路徑的覆蓋映射配置 initialRouteName:設置默認的頁面組件,必須是上面已註冊的頁面組件 initialRouteParams:初始路由參數
能夠只配置RouteConfigs參數
RouteConfigs參數表示各個頁面路由配置,React開發中的 Router路由配置 ,它是讓導航器知道須要導航的路由對應的頁面
RN頁面路由配置:
const AppIndex = StackNavigator( { Task: { screen: Task, //加載首屏須要在navigationOptions裏面配置首頁導航信息 navigationOptions: ({ navigation }) => ({ headerTitle: "首頁", headerBackTitle: null }) }, NewTask: { screen: NewTask }, Redeem: { screen: Redeem }, Rule: { screen: Rule } } );
已經配置好導航器以及對應的路由頁面了,可是要完成頁面之間的跳轉,還須要 navigation;
在導航器中的每個頁面,都有 navigation 屬性
頁面的配置選項 navigationOptions 一般還能夠在對應頁面中去靜態配置,好比在 Redeem 頁面中 (注意:若是默認是首頁的話就不要再頁面中聲明static navigationOptions了) class Redeem extends Component { static navigationOptions = ({ navigation }) => ({ headerTitle: `${navigation.state.params.title}`, headerRight: ( <View style={{ flexDirection: "row" }}> <Text style={{ color: "#333", marginRight: 13 }} onPress={() =>navigation.state.params ? navigation.state.params.jumpToRule() : null }> 兌換規則 </Text> </View> ) }); ..... } 通常子頁面navigationOptions參數最好都在子頁面裏面去配置,不要在首頁到導航參數裏面配置,方便調用本類方法
調用這個方法能夠跳轉到導航器中的其餘頁面,此方法有三個參數
首先在頁面須要跳轉的地方聲明navigate
const { navigate } = this.props.navigation;
而後經過點擊事件調用navigate跳轉
//首頁跳轉積分兌換頁面 <TouchableOpacity style={styles.redeem} onPress={() => navigate("Redeem", { title: "積分兌換" })}> <Text style={styles.redeemText}>積分兌換</Text> </TouchableOpacity> //積分兌換頁面跳轉兌換規則頁面 jumpToRule = () => { const { navigate } = this.props.navigation; navigate("Rule", { title: "積分兌換規則" }); }
state 裏面包含有傳遞過來的參數 params 、 key 、路由名稱 routeName
{ params: { param: 'i am the param' }, key: 'id-1500546317301-1', routeName: 'Redeem' }
使用:
headerTitle: `${navigation.state.params.title}`
更改當前頁面路由的參數,好比能夠用來更新頭部的按鈕或者標題
setParams的使用:
//導航右側按鈕 點擊調用原本方法 headerRight: ( <View style={{ flexDirection: "row" }}> <Text style={{ color: "#333", marginRight: 13 }} onPress={() => navigation.state.params ? navigation.state.params.jumpToRule() : null }> 兌換規則 </Text> </View> )
說明:
若是導航欄上的的按鈕點擊是須要調用本類方法時不能直接this.jumpToRule(),須要在聲明週期的componentDidMount中經過navigation中的setParams把函數註冊到導航器中
componentDidMount() { this.props.navigation.setParams({ jumpToRule: this.jumpToRule }); }
能夠不傳,也能夠傳參數,還能夠傳 null
this.props.navigation.goBack(); // 回退到上一個頁面
this.props.navigation.goBack(null); // 回退到任意一個頁面
this.props.navigation.goBack('Home'); // 回退到Home頁面
dispatch - 發送一個action
組件採用堆棧式的頁面導航來實現各個界面跳轉。它的構造函數:
TabNavigator(RouteConfigs, TabNavigatorConfig) RouteConfigs:頁面tab配置 TabNavigatorConfig:參數配置
screen:和導航的功能是同樣的,對應界面名稱,能夠在其餘頁面經過這個screen傳值和跳轉。 navigationOptions:配置TabNavigator的一些屬性 title:標題,會同時設置導航條和標籤欄的title tabBarVisible:是否隱藏標籤欄。默認不隱藏(true) tabBarIcon:設置標籤欄的圖標。須要給每一個都設置 tabBarLabel:設置標籤欄的title。推薦 導航欄配置 tabBarPosition:設置tabbar的位置,iOS默認在底部,安卓默認在頂部。(屬性值:'top','bottom') swipeEnabled:是否容許在標籤之間進行滑動 animationEnabled:是否在更改標籤時顯示動畫 lazy:是否根據須要懶惰呈現標籤,而不是提早,意思是在app打開的時候將底部標籤欄所有加載,默認false,推薦爲true trueinitialRouteName: 設置默認的頁面組件 backBehavior:按 back 鍵是否跳轉到第一個Tab(首頁), none 爲不跳轉 tabBarOptions:配置標籤欄的一些屬性iOS屬性 activeTintColor:label和icon的前景色 活躍狀態下 activeBackgroundColor:label和icon的背景色 活躍狀態下 inactiveTintColor:label和icon的前景色 不活躍狀態下 inactiveBackgroundColor:label和icon的背景色 不活躍狀態下 showLabel:是否顯示label,默認開啓 style:tabbar的樣式 labelStyle:label的樣式安卓屬性 activeTintColor:label和icon的前景色 活躍狀態下 inactiveTintColor:label和icon的前景色 不活躍狀態下 showIcon:是否顯示圖標,默認關閉 showLabel:是否顯示label,默認開啓 style:tabbar的樣式 labelStyle:label的樣式 upperCaseLabel:是否使標籤大寫,默認爲true pressColor:material漣漪效果的顏色(安卓版本須要大於5.0) pressOpacity:按壓標籤的透明度變化(安卓版本須要小於5.0) scrollEnabled:是否啓用可滾動選項卡 tabStyle:tab的樣式 indicatorStyle:標籤指示器的樣式對象(選項卡底部的行)。安卓底部會多出一條線,能夠將height設置爲0來暫時解決這個問題 labelStyle:label的樣式 iconStyle:圖標樣式
導入必要組件:
import { TabNavigator } from "react-navigation"; import Home from "./category/Home"; import Feedback from "./category/feedback/feedback";
定義TabNavigator:
const MyTab = TabNavigator( { Home: { screen: Home, navigationOptions: ({ navigation }) => ({ headerTitle: "首頁", tabBarLabel: "首頁", headerBackTitle: null }) }, Feed: { screen: Feedback, navigationOptions: ({ navigation }) => ({ headerTitle: "意見反饋", tabBarLabel: "個人", headerBackTitle: null, }) } }, { tabBarComponent: TabBarBottom, tabBarPosition: "bottom", //設置tabbar的位置,iOS默認在底部,安卓默認在頂部。(屬性值:'top','bottom') swipeEnabled: true, //是否容許在標籤之間滑動 animationEnabled: false, //是否在更改標籤時顯示動畫 lazy: true, //是否根據須要懶惰呈現標籤,而不是提早製做,意思是在app打開的時候將底部標籤欄所有加載,默認false,推薦改爲true tabBarOptions: { activeTintColor: "#ff552e", //label和icon的前景色 活躍狀態下(選中) // activeBackgroundColor:'blue',//label和icon的背景色 活躍狀態下 inactiveTintColor: "#333", //label和icon的前景色 不活躍狀態下 showLabel: true, //是否顯示label,默認開啓 showIcon: true, // android 默認不顯示 icon, 須要設置爲 true 纔會顯示 style: { backgroundColor: "#ffffff" }, //tabbar的樣式 labelStyle: { fontSize: 14 // 文字大小 } } } );
const MyTab = TabNavigator( { Home: { screen: Home, navigationOptions: ({ navigation }) => ({ headerTitle: "首頁", tabBarLabel: "首頁", headerBackTitle: null, tabBarIcon: ({ tintColor }) => ( <Image style={styles.imageStyle} source={ tintColor == "#ff552e" ? require("./img/yingxiao/ac-jingxuan.png") : require("./img/yingxiao/jingxuan.png") } /> ) }) }, Feed: { screen: Feedback, navigationOptions: ({ navigation }) => ({ headerTitle: "意見反饋", tabBarLabel: "個人", headerBackTitle: null, headerRight: ( <Text style={{ color: "#333", marginRight: 14, fontSize: 16 }} onPress={() => navigation.state.params ? navigation.state.params.submit() : null }> 提交 </Text> ), tabBarIcon: ({ tintColor }) => ( <Image style={styles.imageStyle} source={ tintColor == "#ff552e" ? require("./img/yingxiao/ac-laidiantong.png") : require("./img/yingxiao/laidiantong.png") } /> ) }) } }, { tabBarComponent: TabBarBottom, tabBarPosition: "bottom", //設置tabbar的位置,iOS默認在底部,安卓默認在頂部。(屬性值:'top','bottom') swipeEnabled: true, //是否容許在標籤之間滑動 animationEnabled: false, //是否在更改標籤時顯示動畫 lazy: true, //是否根據須要懶惰呈現標籤,而不是提早製做,意思是在app打開的時候將底部標籤欄所有加載,默認false,推薦改爲true tabBarOptions: { activeTintColor: "#ff552e", //label和icon的前景色 活躍狀態下(選中) // activeBackgroundColor:'blue',//label和icon的背景色 活躍狀態下 inactiveTintColor: "#333", //label和icon的前景色 不活躍狀態下 showLabel: true, //是否顯示label,默認開啓 showIcon: true, // android 默認不顯示 icon, 須要設置爲 true 纔會顯示 style: { backgroundColor: "#ffffff" }, //tabbar的樣式 labelStyle: { fontSize: 14 // 文字大小 } } } ); const AppIndex = StackNavigator( { Main: { screen: MyTab }, Task: { screen: Task }, NewTask: { screen: NewTask }, Redeem: { screen: Redeem }, Rule: { screen: Rule }, Test: { screen: Test } }, { initialRouteName: "Task", // 默認顯示界面 navigationOptions: { headerTitle: "每日任務", headerBackTitle: null, // headerBackTitle: "返回", headerTintColor: "#333", cardStack: { gesturesEnabled: true //是否容許右滑返回,在iOS上默認爲true,在Android上默認爲false } }, // mode: "card", // 頁面切換模式, 左右是card(至關於iOS中的push效果), 上下是modal(至關於iOS中的modal效果) headerMode: "screen", // 導航欄的顯示模式, screen: 有漸變透明效果, float: 無透明效果, none: 隱藏導航欄 onTransitionStart: () => {}, // 回調 onTransitionEnd: () => {} // 回調 } );