React-Native傻瓜式学习笔记(二):封装Navigator工具类

最近国内外使用React-Native写APP的公司越来越多了,我们公司也不甘落后,将使用React-Native重写APP这个事提上了日程。然而这个任务落到我头上的时候,我本人作为一个Android菜鸡程序猿当即表示“臣妾做不到啊~”,然而并没有什么卵用。没办法,只好硬着头皮现学现卖。这东西刚出时间并不算长,网上完整的系统的参考文章较少,多数都是零碎的知识点,只好在博客里做个笔记,省得忘了以后再去满大街找。。
这一系列笔记内容均仅代表我个人的观点,不保证都是对的

起因

一个真正的APP通常不会只有一个页面,甚至有些大型APP包含了上百的Activity(Android视角),页面之间互相跳转的逻辑错综复杂。虽然Android原生应用可以方便的通过Intent实现各个Activity之间的跳转,但对RN来说就不那么简单了。

一个纯粹使用RN开发的应用,通常在Android原生层面只有一个Activity,RN通过在这个Activity上不断的切换不同的组件(Component)来模拟Activity跳转的过程,而管理组件切换的控件就是Navigator

Navigator的基本使用方法在这里就不多做说明了,可以参考官方文档或自行百度。这里关注的重点在于,如果一个组件需要使用Navigator来切换页面的话,需要将这个Navigator通过传参的方式从最开始定义它的地方一层一层地传递进来——即使这个组件的父组件们根本不需要用到Navigator。这样做的缺点是显而易见的:页面的布局越复杂,这个Navigator的传递就越混乱。

为了解决这个问题,我们需要一个统一管理Navigator的管理员角色。每一个需要使用Navigator的组件,不需要找他的父组件要,全部去找这个管理员,这样就避免了Navigator传来传去传的满世界都是的尴尬。


工具类的实现

为了实现每个需要同一个Navigator的组件都找到同一个管理员,管理员的角色应该是唯一的,因此我们使用单例模式来实现它,这里我们叫它PageUtil。

// PageUtil.js

let instance = null;     // 工具类单例对象
let navi = null;    // 单例中保存的Navigator对象

export default class PageUtil {
    // 在构造函数中实现单例
    constructor() {
        if(!instance){
            instance = this;
        }
        return instance;
    }
    // 为单例对象保存Navigator
    setNavigator = (navigator) => {
        navi = navigator;
    }
}

这样,一个单例的管理员就写好了,然后我们为它添加跳转页面的方法。

// PageUtil.js

let instance = null;     // 工具类单例对象
let navi = null;    // 单例中保存的Navigator对象

export default class PageUtil {
    // 在构造函数中实现单例
    constructor() {
        if(!instance){
            instance = this;
        }
        return instance;
    }

    // 为单例对象保存Navigator
    setNavigator = (navigator) => {
        navi = navigator;
    }

    /**
     * 页面跳转方法
     * @param component 目标组件对象
     * @param params 需要传递的参数组成的对象
     */
    jumpPageWithComponent = (component, params) => {
        if (!params) {
            params = {};
        }
        let route = {
            component: component,
            params: params
        };
        if (navi) {
            navi.push(route)
        }
    }
}

至此,一个简单的Navigator工具类就写好了,下面我们来看看怎么使用。


工具类的使用方法

首先,要使用工具类必须要先定义一个Navigator,并将这个Navigator的实例引用保存在工具类中:

// App.js

import React,{Component} from 'react';
import {Navigator, View, StyleSheet} from 'react-native';
import SplashPage from './SplashPage';
import PageUtil from '../utils/PageUtil';

export default class App extends Component {

    constructor(props) {
        super(props);
        // 初始化工具类
        this.pageUtil = new PageUtil();
    }

    renderScene = (route, navigator) => {
        // 工具类中的Navigator的push方法最终会将我们传入的route对象传到这里
        // 直接使用传过来的route中的内容进行页面跳转
        if (route.component) {
            return <route.component {...route.params}/>
        }
    };

    render() {
        return(
            <View style={styles.container}>
                <Navigator
                    // 这里很重要,使用ref参数获取Navigator实例的引用并set到工具类中
                    // 在setNavigator之前,是无法使用工具类进行页面跳转的
                    ref = {(navi) => {
                        this.pageUtil.setNavigator(navi);
                    }}
                    initialRoute={{
                        component: SplashPage,
                    }}
                    style={styles.navigator}
                    renderScene={this.renderScene}
                />
            </View>
        )
    }
}

let styles = StyleSheet.create({
    container: {
        flex: 1
    },
    navigator: {
        flex: 1
    }
});

Navigator和工具类都准备好后,就可以使用工具类进行页面跳转了,用起来类似这样:

// SplashPage.js

import React,{Component} from 'react';
import {View,Image,StyleSheet,Dimensions} from 'react-native';
import PageUtil from '../utils/PageUtil';
import MainPage from './MainPage';

export default class SplashPage extends Component {

    constructor(props) {
        super(props);
        this.pageUtil = new PageUtil();
    }

    componentDidMount() {
        // 由于是模拟从闪屏跳转到主页,这里使用计时器跳转,延时3this.timer = setTimeout(()=>{
            // 使用工具类进行页面跳转
            this.pageUtil.jumpPageWithComponent(MainPage,{title: '主页'})
        },3000)
    }

    componentWillUnmount() {
        // 页面销毁的时候解绑计时器
        this.timer && clearTimeout(this.timer);
    }

    render() {
        let {width,height} = Dimensions.get("window");
        return(
            <View style={styles.container}>
                <Image 
                    source={require('../res/image/image_splash.png')}
                    style={{width:width, height:height}}
                    resizeMode='cover'
                />
            </View>
        )
    }
}

const styles = StyleSheet.create({
    container: {
        flex:1,
        backgroundColor:'#fff'
    }
})

以上只是一个基本的用法,就不上效果图了。

总结

上面的工具类只实现了通过Component对象指定跳转目标的方法,实际上可以在工具类中通过页面名称、页面类型等等进行页面跳转,按照不同的业务逻辑和产品设计实现不同的跳转逻辑。妈妈再也不用担心我写Component忘了传Navigator了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值