react_native 项目实战 (3) 使用导航页面跳转 (ReactNaviation 完全自定义导航)

前端之家收集整理的这篇文章主要介绍了react_native 项目实战 (3) 使用导航页面跳转 (ReactNaviation 完全自定义导航)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

其他的一些问题 记录下

什么时候 要给函数加上括号:

加括号情况: 当函数需要立即执行的时候(需要立刻返回)

不加括号情况: 当事件需要延迟触发的时候. (比如点击事件的函数)

static propTypes = {

    }
 ```

 static defaultProps = {

    }
propTypes 是用于传入类型的校验

defaultProps 是给props 设置默认的值

https://segmentfault.com/a/1190000007814801

http://blog.csdn.net/vispin/article/details/53002586

先来一张这次写的最终的效果



分析下布局,我的页面,首先顶部是一个导航栏 我的,这个导航栏可以复用之前写的NavigationBar.js,

但是之前的文字是写死的,右边的控件也是写死的,现在需要把文字和右边的控件作为属性传过去

因为顶部控件是通用的 把他抽取出来

我敲下面的代码的时候

遇到的问题.

1,render() 没有 写 return 直接写了一个View 我一直在找这个问题 巨痛苦

2,出现PropTypes is not defined . 原来PropTypes这个东西 需要引入,和Compoent一起引入
在这里记录下

动态传递控件 顶部控件

再分析下 顶部导航栏是由三部分组成 左边视图 中间标题 右边视图

,那么我在NavigationBar里面接收从其他页面传递过来的组件就可以实现
顶部控件是动态的了.

那么现在先改造NavigationBar

/** * Created by liuml on 2017/9/11. */
import React,{Component,PropTypes} from 'react';
import {
    AppRegistry,StyleSheet,Text,View,StatusBar,Platform,Image,TouchableOpacity
} from 'react-native';

export default class NavigationBar extends Component {

    static propTypes = {
        //验证,不传element组件类型,会报错提示
        rightButton: PropTypes.element,leftButton: PropTypes.element
    }

    render() {
        return <View style={styles.container}>
            <View style={styles.container}>
                <StatusBar hidden={false} barStyle="light-content"/>
            </View>
            {/*顶部导航栏*/}
            <View style={styles.navBar}>
                <View style={styles.leftBtnStyle}>
                    {this.props.leftButton}
                </View>
                <View style={styles.titleWrapper}>
                    <Text style={styles.title}>{this.props.title}</Text>
                </View>
                <View style={styles.rightBar}>
                    {this.props.rightButton}
                </View>

            </View>
        </View>
    }
}
const styles = StyleSheet.create({

    container: {
        backgroundColor: '#63B8FF',},statusBar: {
        height: Platform.OS === 'ios' ? 20 : 0
    },navBar: {
        flexDirection: 'row',justifyContent: 'space-between',alignItems: 'center',titleWrapper: {
        flexDirection: 'column',justifyContent: 'center',position: 'absolute',left: 40,right: 40,title: {
        fontSize: 16,color: '#FFF'
    },navBtn: {
        width: 24,height: 24
    },rightBar: {
        flexDirection: 'row',paddingRight: 8
    },leftBtnStyle: {
        flexDirection: 'row',});

可以看到关键的几行代码

static propTypes = {
        //验证,不传element组件类型,会报错提示
        rightButton: PropTypes.element,leftButton: PropTypes.element
    }

这是用于校验传入的左边的和右边的 是不是一个节点

{/*顶部导航栏*/}
            <View style={styles.navBar}>
                <View style={styles.leftBtnStyle}>
                    {this.props.leftButton}
                </View>
                <View style={styles.titleWrapper}>
                    <Text style={styles.title}>{this.props.title}</Text>
                </View>
                <View style={styles.rightBar}>
                    {this.props.rightButton}
                </View>

            </View>

这是给顶部导航栏设置左边中间和右边的控件 通过props传递

然后在PapularPage 里面创建标题栏 右边的控件

/**
 * Created by liuml on 2017/9/11.
 */

import React,{Component} from 'react';
import {
    AppRegistry,ListView,RefreshControl,TouchableOpacity
}from 'react-native';

import NavigationBar from "../compoent/NavigationBar.js"
import ScrollableTabView from "react-native-scrollable-tab-view"
import ProjectRow from "../compoent/ProjectRow"

export default class PapularPage extends Component {


    // 构造
    constructor(props) {
        super(props);
        // 初始状态
        this.state = {
            languages: ["Android","Ios","Java","React","JS"]
        };
    }

    getRightBtn = () => {
        return <View style={{flexDirection: 'row',alignItems: 'center'}}>
            <TouchableOpacity activeOpacity={0.7}>
                <Image source={require('../../res/images/ic_search_white_48pt.png')}
                       style={{width:24,height:24}}></Image>
            </TouchableOpacity>
            <TouchableOpacity activeOpacity={0.7}>
                <Image source={require('../../res/images/ic_more_vert_white_48pt.png')}
                       style={{width:24,height:24}}></Image>
            </TouchableOpacity>
        </View>
    }

    render() {
        return <View style={styles.container}>
            <NavigationBar
                rightButton={this.getRightBtn()}
                title="热门"/>
            <ScrollableTabView
                tabBarBackgroundColor="#63B8FF"
                tabBarActiveTextColor="#FFF"
                tabBarInactiveTextColor="#F5FFFA"
                tabBarUnderlineStyle={{backgroundColor: "#E7E7E7",height: 2}}>
                {
                    this.state.languages.map((item,i) => { return <PopularTab key={`tab${i}`} tabLabel={item}/> }) } </ScrollableTabView> </View> } } class PopularTab extends Component { //这里是Tab 的名字 static defaultProps = { tabLabel: 'android',} // 构造 constructor(props) { super(props); // 初始状态 this.state = { dataSource: new ListView.DataSource({rowHasChanged: (r1,r2) => r1 !== r2}),//是一个优化,节省无用的UI渲染 判断前后数据是否改变 如果改变就更新 isLoading: true }; } /*componentDidMount() { /!*this.setState({ dataSource: this.state.dataSource.cloneWithRows(['first','second','three']) } )*!/ this.loadData(); };*/ //和上面一样的效果 componentDidMount = () => {
        this.loadData();
    }

    //渲染ListView的每一行
    renderRow = (obj) => {
        return <ProjectRow item={obj}></ProjectRow>
        // return <Text>{obj.full_name}</Text>
    }


    //加载数据
    loadData = () => {
        this.setState({isLoading: true});
        fetch(`https://api.github.com/search/repositories?q=${this.props.tabLabel}&sort=stars`)
            .then(response => response.json()) //服务器响应response对象,继续变成json对象
            .then(json => {
                //更新dataSource
                this.setState({
                    dataSource: this.state.dataSource.cloneWithRows(json.items),isLoading: false,});
            })
            .catch((error) => { console.error(error); }).done(); } handleRefresh = () => {
        this.loadData();
    }

    render() {
        return <View style={styles.container}>
            <ListView
                dataSource={this.state.dataSource}
                renderRow={this.renderRow}
                refreshControl={
                    <RefreshControl
                        refreshing={this.state.isLoading}
                        tintColor="#63B8FF"
                        title="正在加载..."
                        titleColor="#63B8FF"
                        colors={['#63B8FF']}
                    />
                }
            ></ListView>
        </View>
    }
}


const styles = StyleSheet.create({
    container: {
        flex: 1
    }
});

最后的做完的效果

总结下我这里做了什么:

  • 把导航栏抽取出来了,让每个页面的导航栏作为props

使用导航@R_551_404@面

https://reactnavigation.org/docs/intro/

这里是英文文档.

使用步骤 npm install –save react-navigation

需要先引入这个 react-navigation

可以看到英文文档有三个导航器 那么我这里只需要用到其中一个StackNavigator 堆导航 类似android的activity栈

具体看下我的另一篇blog http://www.jb51.cc/article/p-yhkxreke-bny.html

写的是基础 使用 我这里需要使用自定义的导航

看过文章后应该知道需要把所有的@R_551_404@面在一个js里面定义一次,如果想使用自定义的导航那么需要把navigation
每个页面都传递让每个页面都持有naviagation.这样才能进行页面跳转

下面说下我是怎么操作的

  1. 首先因为ios 和android 的index.js 的文件内容都差不多那么就把相同的部分抽取出来 抽取成一个Setup.js,然后在index.android.js 和index.ios.js里面调用
  2. 在Setup.js中 使用ReactNaviation,使用这个导航器 需要把所有需要跳转页面在这里定义

下面上代码

这里是index.android.js

/** * Sample React Native App * https://github.com/facebook/react-native * @flow */

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

import SetUp from './js/pages/Setup';
export default class MyApp extends Component {
    render() {
        return (
            <SetUp/>
        );
    }
}
AppRegistry.registerComponent('testP',() => MyApp);

这是Setup.js 注意在所有的ReactNative中的控件首字母必须大写.不然会出错

/** * Created by liuml on 2017/9/17. */

import React,Platform
} from 'react-native';
import {StackNavigator} from 'react-navigation';
import Homepage from "./HomePage";
import MyPage from "../my/MyPage";
import CustomKeyPage from "../my/CustomKeyPage";

//各个页面路由配置
const RouteConfigs = {
    Home: {//首页
        screen: Homepage,MyPage: {//我的
        screen: MyPage,CustomKeyPage: {//自定义分类
        screen: CustomKeyPage,}

//导航器的配置,包括导航器的初始页面、各个页面之间导航的动画、页面的配置选项等等
const NavigatorConfig = {
    initialRouteName: 'Home',// 默认显示界面
    headerMode: 'none',//https://reactnavigation.org/docs/navigators/stack#StackNavigatorConfig

}

//导航注册
const RootNavigator = StackNavigator(RouteConfigs,NavigatorConfig);
export default RootNavigator;

这里需要解释下StackNavigator 是用于跳转的导航 在他的配置中 如果没有

headerMode: ‘none’ 参数会有自己默认的导航条 这里的意思就是隐藏默认的导航条

还有一些其他的参数看下我的注释和我之前写的一篇文章http://www.jb51.cc/article/p-yhkxreke-bny.html 就应该明白了

自定义ReactNativiation跳转

我现在需要做的是在<我的>页面进行跳转,跳转到<自定义分类>页面.

代码

/** * Created by liuml on 2017/9/16. */
import React,RefreshControl
}from 'react-native';

import  NavigationBar from "../compoent/NavigationBar";
/** * 我的页面 */
export default class MyPage extends Component {


    //navigation 里的方法有navigate 是用于页面跳转 goBack是用于页面返回
    render() {
        const navigation = this.props.navigation.navigate;
        return <View style={styles.container}>
            <NavigationBar
                title="我的"/>
            <View style={{flexDirection: 'column',marginTop: 30}}>
                <Text onPress={() => {
                    navigation('CustomKeyPage',{source: '自定义分类'});
                }}>自定义分类</Text>
            </View>
        </View>
    }
}

const styles = StyleSheet.create({

    container: {
        flex: 1
    }
})

可以看到我使用navigation 进行跳转 注意这个navigation 是从HomePage.js初始的

时候就有的,我把这个navigation 从HomePage传到了这个MyPage.js 页面 下面是传递的代码

因为HomePage.js 只改了传递参数的代码 我就只截取这一点代码 我参数传递是通过

es6语法 遍历传递的 三个点表示每一个参数一个个的传过去

<TabNavigator.Item
                    selected={this.state.selectedTab === 'my'}
                    slectedTitleStyle={{color: '#0F0'}}
                    renderIcon={() => <Image style={styles.icon}
                                             source={require('../../res/images/ic_my.png')}/>}
                    renderSelectedIcon={() =>
                        <Image style={[styles.icon,{tintColor: '#63B8FF'}]}
                               source={require('../../res/images/ic_my.png')}/>}
                    onPress={() => this.setState({selectedTab: 'my'})}
                    title="我的">

                    <MyPage {...this.props}/>
                </TabNavigator.Item>

可以看到主要就是这个代码起作用

<MyPage {...this.props}/>

-自定义分类页面

/** * Created by liuml on 2017/9/17. */
import React,TouchableOpacity
} from 'react-native';
/** * 自定义分类页面 */
import NavigationBar from '../compoent/NavigationBar'

export default class CustomKeyPage extends Component {

    handleBack = () => {
        this.props.navigation.goBack();
    }
    getLeftBtn = () => {
        return <View style={{flexDirection: 'row',alignItems: 'center'}}>
            <TouchableOpacity
                activeOpacity={0.7}
                onPress={this.handleBack}>
                <Image source={require('../../res/images/ic_arrow_back_white_36pt.png')}
                       style={{width: 24,height: 24}}/>
            </TouchableOpacity>
        </View>;
    }

    getRightBtn = () => {
        return <View style={{flexDirection: 'row',alignItems: 'center'}}>
            <TouchableOpacity activeOpacity={0.7}>
                <View style={{marginRight: 10}}>
                    <Text style={{fontsize: 16,color: '#FFF'}}>保存</Text>
                </View>
            </TouchableOpacity>
        </View>
    }

    render() {

        return <View style={styles.container}>
            <NavigationBar
                title="自定义分类"
                rightButton={this.getRightBtn()}
                leftButton={this.getLeftBtn()}/>
            <Text onPress={() => {
                this.handleBack();
            }}>CustomKeyPage</Text>
        </View>
    }
}

const styles = StyleSheet.create({

    container: {
        flex: 1
    },});

注意我这里是怎么返回的

this.props.navigation.goBack();

navigation有goBack()方法 点击箭头后调用 下面来一张最终的效果

github 地址 还没写完会继续更新

https://github.com/liudao01/ReactNativeProject

猜你在找的React相关文章