【问题标题】:ReactJs - Horizontal Mobile Menu using ReactCSSTransitionGroupReactJs - 使用 ReactCSSTransitionGroup 的水平移动菜单
【发布时间】:2016-03-09 18:50:01
【问题描述】:

移动菜单 UI:(PanelGroup 与祖先和后代组件共享)

  1. 初始 MenuPanel 将 PanelGroup(在 props 中带有 navItems 数组)传递给 DOM。
  2. 传递的一些 navItems 有 subNavItems。
  3. 具有 subNavItems 的那些也将 PanelGroup 及其子项传递给 DOM。

预期会发生什么:

  1. 当触发 MenuPanel 时,会列出 navItems,并且具有 subNavItems 的那些具有标记供用户单击以显示 subNavItems。

  2. 当 subNavItems 被选中时,所有之前的 navItems 都将消失,只显示 subNavItems。

期望的结果:在家庭法 navItem 被点击后,链上的项目消失并且选定的子节点出现

实际结果:点击Family Law navItem后,链上的项目保留,选定的子节点写在它们上面

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

导出默认类 MobileNavButton 扩展组件 {

  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>
    );
  }
}

菜单面板:

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>
    );
  }
}

【问题讨论】:

    标签: reactjs


    【解决方案1】:

    我选择了 ReactCSSTransitionGroup

    这是实现我的目标的示例代码:

    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>
    

    【讨论】:

      猜你喜欢
      • 2014-09-23
      • 2013-06-30
      • 2017-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-29
      • 1970-01-01
      相关资源
      最近更新 更多