ReactJs - 使用ReactCSSTransitionGroup的水平移动菜单

时间:2016-03-09 18:50:02

标签: reactjs

移动菜单用户界面:( PanelGroup与祖先和后代组件共享)

  1. Inital MenuPanel将PanelGroup(在props中使用navItems数组)传递给DOM。
  2. 传递的一些navItems有subNavItems。
  3. 具有subNavItems的人也将PanelGroup及其子项传递给DOM。
  4. 预期会发生什么:

    1. 当触发MenuPanel时,会列出navItems,而带有subNavItems的列表会让用户点击以显示subNavItems。

    2. 当选择了subNavItems时,所有以前的navItems都将消失,只显示subNavItems。

    3. 期望的结果:链上的项目消失了&单击Family Law navItem后出现选定的子节点

      enter image description here

      实际结果:单击“家庭法”navItem后,链上的项目仍保留,选定的子节点将在其上面写入

      enter image description here

      MobileNavButton :(上面的蓝色菜单按钮)

      导出默认类MobileNavButton扩展了Component {

        constructor(props) {
          super(props);
          this.state = {
            showMobileMenuGroup: false
          }
        }
      
        static propTypes = {
          btn: PropTypes.object.isRequired,
          viewDevice: PropTypes.object.isRequired
        };
      
        handleShowHide(e) {
          e.preventDefault();
          const doesShow = !this.state.showMobileMenuGroup;
          this.setState({showMobileMenuGroup: doesShow});
        }
      
        render() {
          const { btn, viewDevice } = this.props;
          return (
            <section>
                 .....
              { btn.clickEvent ?
                <li ref="menuButton">
                  <a onClick={ this.handleShowHide.bind(this) }>
                    <icon className={ btn.icon }/>
                    <h2>{ btn.innerText }</h2>
                  </a>
                  <MobileMenuPanel childPages={ btn.childPages } showMobileMenuGroup={ this.state.showMobileMenuGroup } />
                </li> : ''
              }
            </section>
          );
        }
      }
      

      MenuPanel:

      export default class MobileMenuPanel extends Component {
      
        static propTypes = {
          childPages: PropTypes.array.isRequired,
          showMobileMenuGroup: PropTypes.bool.isRequired
        };
      
        render() {
          const { showMobileMenuGroup } = this.props;
          const { childPages } = this.props;
          return (
            <div className='imenupanel' style={showMobileMenuGroup ? showSlide : hideSlide } >
              <MobileMenuGroup childPages={ childPages } showMobileMenuGroup={showMobileMenuGroup ? true : false } />
            </div>
          );
        }
      }
      

      MobileMenuGroup:

      export default class MobileMenuGroup extends Component {
      
        static propTypes = {
          childPages: PropTypes.array.isRequired,
          showMobileMenuGroup: PropTypes.bool.isRequired
        };
      
        render() {
          const { childPages } = this.props;
          const { showMobileMenuGroup } = this.props;
          return (
            <div className='imenu' style={  showMobileMenuGroup ? { display: 'block' } : { display: 'none' } }>
              {
                childPages.map((childPage, idx) => {
                  return (
                    <MobileNavMenuItem key={ idx } menuItem={ childPage }/>
                  )
                })
              }
            </div>
          );
        }
      }
      

      MobileNavMenuItem:

      export default class MobileNavMenuItem extends Component {
      
        constructor(props) {
          super(props);
          this.state = {
            showMobileMenuGroup: false
          }
        }
      
        static propTypes = {
          menuItem: PropTypes.object.isRequired
        };
      
        showChildren(e) {
          e.preventDefault();
          let showMobileMenuGroup = !this.state.showMobileMenuGroup;
          this.setState({ showMobileMenuGroup: showMobileMenuGroup });
        }
      
        render() {
          const { menuItem } = this.props;
          const childPages = menuItem.childPages !== undefined ? menuItem.childPages.length : 0;
          let menuItemsStyle = childPages > 0 ? 'imenuitem iright' : 'imenuitem'
          return (
                <div className={ menuItemsStyle } pageId={ menuItem.pageId } childPages={ childPages }
                  >
                  { childPages > 0 ?
                  <span onClick={ this.showChildren.bind(this) } >
                      <div style={ { color: '#FFFFFF', padding: '12px 15px' } }>{ menuItem.title }</div>
                    <MenuPanelGroup childPages={ menuItem.childPages } showMobileMenuGroup={ this.state.showMobileMenuGroup } />
                    </span>
                    :
                    <a href={ menuItem.linkTo }>{ menuItem.title }</a>
                  }
                </div>
          );
        }
      }
      

1 个答案:

答案 0 :(得分:0)

我选择了ReactCSSTransitionGroup

enter image description here

以下是实现目标的示例代码:

<强> Index.js

//    "react": "^0.14.7",
//    "react-addons-css-transition-group": "^0.14.7",
//    "react-dom": "^0.14.7",

import React from 'react';
import { render } from 'react-dom';
const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
const SlideTransition = React.createClass({
  propTypes: {
    depth: React.PropTypes.number.isRequired,
    name: React.PropTypes.string
  },
  getDefaultProps() {
    return {
      name: 'slider'
    };
  },
  getInitialState() {
    return {direction: 'right'};
  },
  componentWillReceiveProps(newProps) {
    const direction = newProps.depth > this.props.depth ? 'right' : 'left';
    this.setState({direction});
  },
  render() {
    const {name, depth} = this.props;
    const outerProps = {
      className: `${name}-outer-wrapper ${this.props.className}`
    };
    console.log(`name: ${name} depth: ${depth}`);
    const transProps = {
      component: 'div',
      transitionName: `${name}-${this.state.direction}`,
      className: `${name}-transition-group`
    };
    const innerProps = {
      ref: 'inner',
      key: depth,
      className: `${name}-inner-wrapper` // imenupanel
    };

    return <div {...this.props} {...outerProps}>
        <ReactCSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={300}  {...transProps}>
        <div {...innerProps}>
          {this.props.children}
        </div>
      </ReactCSSTransitionGroup>
    </div>;
  }
});
const Browser = React.createClass({
  getInitialState() {
    return {
      path: []
    }
  },
  navUp() {
    this.setState({path: this.state.path.slice(0, -1)})
  },
  navDown(index) {
    this.setState({path: this.state.path.concat(index)})
  },
  render() {
    const {path} = this.state;
    const items = path.reduce(function(items, key) {
      return items[key].children;
    }, this.props.items);
    console.log(path);
    console.log(this.props.items);
    return <div className="browser">

      <SlideTransition depth={path.length} className="items-container">
        <div className="menuItem">{path.length > 0 ? <a style={ { color: 'white' } }  onClick={this.navUp}>Back</a> : 'Home'}</div>
        {items.map(function(item, index) {
          if (item.children) {
            return <div key={item.name} style={ { clear: 'both' } } className="menuItem" >
              <a style={ { display: 'inline!Important', color: 'white' } } href="#">{item.name}</a>
              <a style={ { display: 'inline!Important', float: 'right', background: 'transparent' } } className="arrow" onClick={e => this.navDown(index)} key={item.name}>&nbsp;</a></div>;
          } else {
            return <div className="menuItem" key={item.name} key={item.name}><a href="#"style={ { color: 'white' } }>{item.name}</a></div>;
          }
        }.bind(this))}
      </SlideTransition>

    </div>;
  }
});
const data = [
  {name: 'Animal', children: [
    {name: 'Land', children: [
      {name: 'Cheetah'},
      {name: 'Ant'},
    ]},
    {name: 'Air', children: [
      {name: 'Eagle'}
    ]},
    {name: 'Water', children: [
      {name: 'Water 1', children: [{name: 'Level'}]},
      {name: 'Water 2', children: [
        {name: 'Water 2', children: [
          {name: 'Water 2 -1'},
          {name: 'Water 2 -2', children: [
            {name: 'Water 2-2-1'},
            {name: 'Water 2-2 -2'},
            {name: 'Water 2-2-3'}
          ]},
          {name: 'Water 2 -3'}
        ]}
      ]}
    ]}
  ]},
  {name: 'Vegetable', children: [
    {name: 'Broccoli'},
    {name: 'IE6'},
  ]},
  {name: 'Mineral', children: [
    {name: 'Granite'},
    {name: 'Uraninite'},
  ]},
];

render(<Browser items={data} />, document.getElementById('MobileNav'));

index.html样式

   <style>
        a {
            cursor: pointer;
            display: block;
            color:#fff;
        }

        .items-container {
            max-width: 20rem;
            border: 2px solid #000;
            border-radius: .25rem;
        }

        .arrow {
            padding: .25rem .5rem;
        }

        .menuItem {
            color: #FFFFFF;
            font-size: 15px;
            border-bottom: solid 1px #5a5a5a;
            padding: 10px 0 10px 10px;
        }

        a.arrow:after {
            content: '\e0ea';
            color: #fff;
            font-family: 'icomoon-ult';
            font-style: normal;
            font-weight: normal;
            text-transform: none;
        }

        a.item:hover {
            background: #eee;
        }

        /* Generic slider styles */

        .slider-outer-wrapper {
            position: relative;
            overflow: hidden;
            transition: max-height .2s ease-in;
        }

        .slider-transition-group {
            width: 200%;
            overflow: hidden;
        }

        .slider-inner-wrapper {
            background-color: #000;
            width: 50%;
            float: right;
            transition: all .2s ease-in-out;
            height: 400px;
        }

        .slider-inner-wrapper:first-child {
            position: relative;
            left: -50%;
        }

        .slider-right-enter {
            transform: translate3d(100%, 0, 0);
        }

        .slider-left-enter {
            transform: translate3d(-100%, 0, 0);
        }

        .slider-right-enter-active,
        .slider-left-enter-active,
        .slider-right-leave,
        .slider-left-leave {
            transform: translate3d(0, 0, 0);
        }

        .slider-right-leave-active {
            transform: translate3d(-100%, 0, 0);
        }

        .slider-left-leave-active {
            transform: translate3d(100%, 0, 0);
        }
    </style>