从react-native的导航器按钮

时间:2016-08-31 16:01:18

标签: javascript reactjs react-native

这是一个我在不同的情况下看到的问题,没有任何直接的解决方案。我也被一些人问过,我正在展示一些示例,以便我如何使用导航来执行我想要的代码,因为他们大多数已经使用第三方解决方案或创建了自己的导航标题使用<View>

对于有某些背景的问题,这是我们正在努力实现的目标:

class Example extends Component {
    componentRouteMapper() {
        switch(route.id) {
            case 'home' return <Home navigator={navigator} { ...this.props } />
        }
    }

    navigationBarRouteMapper = {
        LeftButton: (route, navigator, index, navState) => {
            return <TouchableOpacity onPress={this.onLeftPressed.bind(this)}>
                <Text>Left Button</Text>
            </TouchableOpacity>
        },
        RightButton: (route, navigator, index, navState) => {
            // ... Same as left
        },
        Title: (route, navigator, index, navState) => {
            return <Text>{route.id}</Text>
        }
    }

    render() {
        return <Navigator initialRoute={{id: 'home'}}
            renderScene={this.componentRouteMapper}
            navigationBar={
                <Navigator.NavigationBar { ...this.props } 
                    routeMapper={this.navigationBarRouteMapper}/>
            }

    }
}

当然,您希望能够在渲染组件的上下文中处理导航栏逻辑。在这种情况下:<Home />并且我们希望能够从该组件活动实例共享状态/道具。即使您在主组件中声明了onLeftPressed(),执行上述代码也会导致错误,如下所示:

export default class Home extends Component {

    onLeftPressed() {
        console.log('Pressed left button')
    }

    render() {
        return <View>
            <Text>Home Component</Text>
        </View>
    }
}

所以问题就在于......如何从onRightPressed()

致电navigationBarRouteMapper

1 个答案:

答案 0 :(得分:1)

它实际上非常简单,虽然还有其他方法,例如在路由器中注入组件,但考虑到我的应用程序使用Reduxconnect()方法传递给Route对象是有点麻烦。

所以,我提出了一个简单但有效的解决方案,无论您使用什么来管理您的州,它都能正常运行。 <强>注射即可。没错,只需注入您需要直接调用navigation对象的内容即可。

可以通过navigation从组件中访问this.props.navigator对象,幸运的是,Javascript对象是可变的,并且通过引用自然传递。这意味着我们对导航器对象所做的任何更改都将反映在注入navigationBarRouteMapper

的导航器中

所以,首先让我们改变一些代码:

navigationBarRouteMapper = {
    LeftButton: (route, navigator, index, navState) => {
        return <TouchableOpacity onPress={navigator.__onLeftNavButtonPressed}>
            <Text>Left Button</Text>
        </TouchableOpacity>
    },
    RightButton: (route, navigator, index, navState) => {
        // ... Same as left
    },
    Title: (route, navigator, index, navState) => {
        return <Text>{navigator.navTitle || route.id}</Text>
    }
}

您注意到我已将onPress值从{this.onLeftPressed.bind(this)}更改为{navigator.__onLeftNavButtonPressed}现在显然您可以更改正在使用的名称,但我喜欢双下划线前缀。

您还会看到我更改了标题以返回{navigator.navTitle || route.id}而不仅仅是route.id,这意味着它将使用导航器中的navTitle属性(如果& #39;可用,如果不可用,那么它将使用堆栈顶部的路由ID。

现在让我们对<Home />组件进行更改,以便我们的navigationBarRouteMapper执行我们想要的代码。

class Home extends Component {

    constructor(props) {
        super(props)
        var navigator = this.props.navigator
        navigator.navTitle = 'Home'
        navigator.__onLeftNavButtonPressed = this.onLeftPressed.bind(this)
    }

    onLeftPressed() {
        console.log('Pressed left button')
    }

    render() {
        return <View>
            <Text>Home Component</Text>
        </View>
    }
}

正如您所看到的,唯一改变的是我们添加了一个constructor(...),它将函数和标题注入navigator对象。现在,如果您点击左侧按钮,您将执行onLeftPressed组件内的Home功能。

但是,您可以通过创建自定义组件子类来进一步抽象这一点。例如:

import React, { Component } from 'react'

export default class NavComponent extends Component {
    constructor(props) {
        super(props)
        console.warn('Constructed')
        var navigator = this.props.navigator
        navigator.navbarTitle = this.__onNavTitleRequested();
        navigator.__onLeftNavButtonPressed = this.__onLeftNavButtonPressed.bind(this)
        navigator.__onRightNavButtonPressed = this.__onRightNavButtonPressed.bind(this)
    }


    __onLeftNavButtonPressed() {

    }

    __onRightNavButtonPressed() {

    }

}

这确保始终设置左右导航按钮功能,即使它们不执行任何操作也会阻止因尝试调用未定义函数而导致的应用程序错误。您还会注意到有__onNavTitleRequested的引用,但是没有默认函数,这是为了确保子类必须定义__onNavTitleRequested,否则应用程序将运行不正常。这是为了保护您在标题栏中没有标题错误的组件,因为如果您没有设置标题,它将始终使用最后设置的标题。

实现这一点的一个例子如下:

import React from 'react'
import NavComponent from './path/to/nav-component.js'

export default class Home extends NavComponent {
    __onNavTitleRequested() {
        return 'Home'
    }

    __onLeftNavButtonPressed() {
        console.log('Left navigation button pressed')
    }

    __onRightNavButtonPressed() {
        console.log('Right navigation button pressed')
    }

    render() {
        return <View>
            <Text> Home Component </Text>
        </View>
    }
}

这将向左/右按钮注册一个事件,并设置Home组件的标题。您也可以向Navigator对象注入更多信息,例如,如果您想要一个返回true或false的__hasNavigationBar函数来隐藏整个导航栏,或者可能需要一个__rightNavButton函数来返回组件显示在右侧按钮上,而不仅仅是一个TouchableOpacity按钮。

正如我之前所说的那样,还有其他方法可以做到这一点,但考虑到我在我的应用程序中使用Redux似乎是最简单的,而且我没有遇到任何问题。&lt; < / p>