带有路线或导航的 react-native-side-menu 的完整工作示例 [关闭]

Posted

技术标签:

【中文标题】带有路线或导航的 react-native-side-menu 的完整工作示例 [关闭]【英文标题】:Full working example of react-native-side-menu with routes or navigation [closed] 【发布时间】:2016-08-14 17:57:36 【问题描述】:

我发现很少有帖子给出了一些关于如何将导航\路由与 react-native-side-menu 集成的“提示”,遗憾的是没有找到任何显示此类功能的完整工作示例的帖子。

我也不确定导航\路线最简单的实现是什么,以及这两个选项之间有什么区别(当然这不是专门针对侧边菜单,但在我的情况下应该结合在一起)。

任何人都可以指出这样的例子吗?

【问题讨论】:

【参考方案1】:

所以最终我能够集成标准的 Navigator,如 Facebook 的官方示例代码所示:

https://github.com/facebook/react-native/tree/master/Examples/UIExplorer/Navigator

使用 react-native-side-menu 组件,整个代码如下所示:

'use strict';

var React = require('react');
var ReactNative = require('react-native');
var SideMenu = require('react-native-side-menu');

var 
  Component,
  Navigator,
  AppRegistry,
  View,
  Text,
  Image,
  StyleSheet,
  ScrollView,
  TouchableOpacity
 = ReactNative;

class FirstPage extends Component 
    render() 
      return (
        <View style=styles.page><Text style=styles.pageContent>First Page</Text></View>
      );    
  


class FirstPageMenu extends Component 

    constructor(props) 
        super(props);
        this.state = ;
    

    toggle() 
        this.setState(
          isOpen: !this.state.isOpen,
        );
    

    updateMenuState(isOpen) 
        this.setState( isOpen, );
    

    onMenuItemSelected = (item) => 
        this.setState(
            isOpen: false,      
            selectedItem: item,
        );
        this.props.navigator.replace( id: item );
    

    render() 

        const menu = <Menu onItemSelected=this.onMenuItemSelected navigator=this.props.navigator/>;

        return (
            <SideMenu
              menu=menu
              isOpen=this.state.isOpen
              onChange=(isOpen) => this.updateMenuState(isOpen)>
                <MenuButton onPress=() => this.toggle()/>
                <FirstPage/>
            </SideMenu>                
        );
    
;

class SecondPage extends Component 
     ...


class SecondPageMenu extends Component 
     ...


class ThirdPage extends Component 
     ...


class ThirdPageMenu extends Component 
     ...


class MenuNavigator extends Component 

  constructor(props) 
    super(props);
    this._setNavigatorRef = this._setNavigatorRef.bind(this);
  

  renderScene(route, nav) 
    switch (route.id) 
      case 'first':
        return <FirstPageMenu navigator=nav />;
      case 'second':
        return <SecondPageMenu navigator=nav />;
      case 'third':
        return <ThirdPageMenu navigator=nav />;
      default:
        return <FirstPageMenu navigator=nav />;
    
  

  render() 
    return (
      <Navigator
        ref=this._setNavigatorRef
        initialRoute=id: 'first'
        renderScene=this.renderScene
        configureScene=(route) => 
          if (route.sceneConfig) 
            return route.sceneConfig;
          
          return Navigator.SceneConfigs.FloatFromBottom;
        
      />
    );
  

  componentWillUnmount() 
    this._listeners && this._listeners.forEach(listener => listener.remove());
  

  _setNavigatorRef(navigator) 
    if (navigator !== this._navigator) 
      this._navigator = navigator;

      if (navigator) 
        var callback = (event) => 
          console.log(
            `NavigatorMenu: event $event.type`,
            
              route: JSON.stringify(event.data.route),
              target: event.target,
              type: event.type,
            
          );
        ;
        // Observe focus change events from the owner.
        this._listeners = [
          navigator.navigationContext.addListener('willfocus', callback),
          navigator.navigationContext.addListener('didfocus', callback),
        ];
      
    
  
;

class MenuButton extends Component 

  handlePress(e) 
    if (this.props.onPress) 
      this.props.onPress(e);
    
  

  render() 
    return (
      <View style=styles.menuButton >
        <TouchableOpacity 
          onPress=this.handlePress.bind(this)
          style=this.props.style>
          <Text>this.props.children</Text>
          <Image
            source= uri: 'http://i.imgur.com/vKRaKDX.png', width: 40, height: 40,  />        
        </TouchableOpacity>      
      </View>
    );
  


class Menu extends Component 

  static propTypes = 
    onItemSelected: React.PropTypes.func.isRequired,
  ;

  constructor(props) 
      super(props);
  

  render() 

    return (

      <ScrollView scrollsToTop=false style=styles.menu>

        <Text
          onPress=() => this.props.onItemSelected('first')
          style=styles.item>
          First
        </Text>

        <Text
          onPress=() => this.props.onItemSelected('second')
          style=styles.item>
          Second
        </Text>

        <Text
          onPress=() => this.props.onItemSelected('third')
          style=styles.item>
          Third
        </Text>
      </ScrollView>
    );
  
;

var styles = StyleSheet.create(
    menuButton: 
        marginTop: 20,
        backgroundColor: '#777'
    ,
    menu: 
      flex: 1,
      width: window.width,
      height: window.height,
      padding: 20,
    ,
    item: 
      fontSize: 16,
      fontWeight: '300',
      paddingTop: 20,
    ,    
    page: 
        flex: 1,
        alignItems: 'center',
        backgroundColor: '#777'
    ,
    pageContent: 
        flex: 1,
        alignItems: 'center',
        top: 200,
    ,
    menu: 
      flex: 1,
      width: window.width,
      height: window.height,
      padding: 20,
    ,
    item: 
      fontSize: 16,
      fontWeight: '300',
      paddingTop: 20,
  ,   
);

module.exports = MenuNavigator;

并且索引文件应该只指向导航器:

const React = require('react-native');
const  AppRegistry,  = React;
const MenuNavigator = require('./SideMenuWithNavigation');

AppRegistry.registerComponent('MyApp', () => MenuNavigator);

【讨论】:

有点棘手但有效!谢谢! 我想在单击侧面菜单中的注销图标时显示警报。这段代码有可能吗? 代替 this.props.onItemSelected 您可以为菜单中某些特定项目的 onPress 事件调用任何其他方法【参考方案2】:

如果您指的是抽屉菜单,请检查 react-native-material-design 和给定的演示应用。

【讨论】:

我说的是这个组件:github.com/react-native-fellowship/react-native-side-menu【参考方案3】:

我的 Github 上有一个带有 react-native-side-menunavigator 的启动器。

这个初学者也使用redux(不会阻止回答如何处理导航器+侧边菜单)。

在使用侧边菜单时,routingtrick 用于替换之前的路线以防止其堆叠(就像在普通导航中一样):

  navigate(route) 
    const routeStack      = [].concat(this.refs.navigator.getCurrentRoutes());
    const previousRouteId = routeStack[routeStack.length - 1].id;
    if (route.id !== previousRouteId) 
      this.refs.navigator.replace(route);
    

    if (this.state.sideMenuOpened) 
      this.closeSideMenu();
    
  

检查我的启动器reactNativeReduxFastStarter

快速预览代码:

import React, 
  Component
                           from 'react';
import 
  StyleSheet,
  Text,
  Dimensions,
  Navigator,
  StatusBar
                           from 'react-native';
import SideMenu             from 'react-native-side-menu';
import Icon                 from 'react-native-vector-icons/Ionicons';
import  AppRoutes         from '../../../common/config';
import 
  SideMenuContent,
  Button
                           from '../../components';
import Home                 from '../home';
import AppState             from '../appState';

const SCREEN_WIDTH = Dimensions.get('window').width;

class App extends Component 
  constructor(props) 
    super(props);
    this.init();
  

  init() 
    this.state = 
      sideMenuOpened: false
    ;
  

  openSideMenu() 
    this.setState(
      sideMenuOpened : false
    );
  

  closeSideMenu() 
    if (this.state.sideMenuOpened) 
      this.setState(
        sideMenuOpened : false
      );
    
  

  toggleSideMenu() 
    this.setState(
      sideMenuOpened: !this.state.sideMenuOpened
    );
  

  updateSideMenuState(isOpened) 
    this.setState(
      sideMenuOpened: isOpened
    );
  

  navigate(route) 
    const routeStack      = [].concat(this.refs.navigator.getCurrentRoutes());
    const previousRouteId = routeStack[routeStack.length - 1].id;
    if (route.id !== previousRouteId) 
      this.refs.navigator.replace(route);
    

    if (this.state.sideMenuOpened) 
      this.closeSideMenu();
    
  

  renderScene(route, navigator) 
    switch (route.id) 
    case 1:
      const route1 = AppRoutes.getRouteFromRouteId(1);
      return (
        <Home
          ref=route1.refView
          navigator=navigator
          navigate=(toRoute)=>this.navigate(toRoute)
        />
      );
    case 2:
      const route2 = AppRoutes.getRouteFromRouteId(2);
      return (
        <AppState
          ref=route2.refView
          navigator=navigator
          navigate=(toRoute)=>this.navigate(toRoute)
        />
      );
    default:
      return (
        <Home
          ref=route1.refView
          navigator=navigator
          navigate=(toRoute)=>this.navigate(toRoute)
        />
      );
    
  

  renderRouteMapper() 
    const routes = AppRoutes.getAllRoutes();
    return  
      Title : (route, navigator, index, navState) => 
        const currentRouteId  = navState.routeStack[index].id;
        return (
          <Text style=styles.titleNavText>
            routes[currentRouteId - 1].navbar.navBarTitle
          </Text>
        );
      ,
      LeftButton : (route, navigator, index, navState) => 
        const currentRouteId  = navState.routeStack[index].id;
        return (
          <Button
            style=styles.leftNavButton
            onPress=(e)=>this.toggleSideMenu(e)
            >
            <Icon
              name=routes[currentRouteId - 1].navbar.navBarLeftIconName
              size=32
              color='#333333'
            />
          </Button>
        );
      ,
      RightButton : (route, navigator, index, navState) => 
        return null;
      
    ;

  

  render() 
    StatusBar.setBarStyle('light-content', true);
    const DEFAULT_ROUTE =  id: 1, refView: 'HomeView' ;

    return (
      <SideMenu
        menu=<SideMenuContent
                backGndColor="#ECECEC"
                navigate=(route)=>this.navigate(route)
              />
        isOpen=this.state.sideMenuOpened
        onChange=(isOpened) => this.updateSideMenuState(isOpened)
        bounceBackOnOverdraw=false
        openMenuOffset=SCREEN_WIDTH * 0.8
        >
        <Navigator
          ref="navigator"
          initialRoute= DEFAULT_ROUTE 
          sceneStyle= styles.navigator 
          renderScene=(route, navigator)=>this.renderScene(route, navigator)
          configureScene=()=>Navigator.SceneConfigs.Fadeandroid
          navigationBar=
            <Navigator.NavigationBar
              routeMapper=this.renderRouteMapper()
              style=styles.navBar
            />
          
        />
      </SideMenu>
    );
  


const styles = StyleSheet.create(
  navigator: 
    backgroundColor: '#fff',
    borderLeftWidth: 0.5,
    borderLeftColor: '#F1F1F1',
  ,
  navBar: 
    backgroundColor: '#fff',
    borderWidth:      0.5,
    borderColor:    '#F1F1F1'
  ,
  leftNavButton : 
    flex            : 1,
    flexDirection   : 'column',
    alignItems      : 'center',
    marginTop       : 4,
    paddingTop      : 0,
    paddingBottom   : 10,
    paddingLeft     : 20,
    paddingRight    : 10
  ,
  rightNavButton : 
    flex            : 1,
    flexDirection   : 'column',
    alignItems      : 'center',
    marginTop       : 4,
    paddingTop      : 6,
    paddingBottom   : 10,
    paddingLeft     : 10,
    paddingRight    : 10
  ,
  titleNavText : 
    marginTop   : 14,
    color       : '#333333'
  
);

export default App;

【讨论】:

【参考方案4】:

你可以在 github 上查看这个完整的 sidemenu 项目。本项目包含ToolbarAndroid、路由、DrawerLayoutAndroid、溢出菜单等组件。

https://github.com/darde/react-native-sidemenu

【讨论】:

以上是关于带有路线或导航的 react-native-side-menu 的完整工作示例 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

React-router:防止导航到目标路线

在路线之间去除颤振导航

React&Material UI-如何根据路线删除导航按钮/链接?

如何使用底部导航栏从脚手架主体内部推送路线?

高德地图怎么导航高铁路线

带有多个离线地图的 iOS 导航应用程序:使用哪个库?