移动菜单用户界面:( PanelGroup与祖先和后代组件共享)
预期会发生什么:
当触发MenuPanel时,会列出navItems,而带有subNavItems的列表会让用户点击以显示subNavItems。
当选择了subNavItems时,所有以前的navItems都将消失,只显示subNavItems。
期望的结果:链上的项目消失了&单击Family Law navItem后出现选定的子节点
实际结果:单击“家庭法”navItem后,链上的项目仍保留,选定的子节点将在其上面写入
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>
);
}
}
答案 0 :(得分:0)
我选择了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}> </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>