import React,{PropTypes} from 'react';
import Component from '../utils/Component';
import classnames from 'classnames';
import {setPhoenixPrefix, closest} from '../utils/Tool';
import MenuHeader from './MenuHeader';
import MenuBody from './MenuBody';
import MenuNav from './MenuNav';
import MenuList from './MenuList';
import MenuItem from './MenuItem';
/**
* <h5>菜单组件,主要包括组件:</h5>
* <strong><a href='../classes/Menu.html'>Menu 菜单</a></strong><br/>
* <strong><a href='../classes/MenuHeader.html'>MenuHeader 菜单头部</a></strong><br>
* <strong><a href='../classes/MenuBody.html'>MenuBody 菜单主体</a></strong><br>
* <strong><a href='../classes/MenuNav.html'>MenuNav 菜单导航</a></strong><br>
* <strong><a href='../classes/MenuList.html'>MenuList 菜单导航列表</a></strong><br>
* <strong><a href='../classes/MenuItem.html'>MenuItem 菜单导航列表项</a></strong><br>
* <h6>点击以上链接或者左侧导航栏的组件名称链接进行查看</h6>
* @module 菜单组件
* @main 菜单组件
* @static
*/
/**
* 菜单组件<br/>
- 可通过visible设置菜单初始是否可见,默认不可见。
- 不设置scrollCeiling时默认菜单不吸顶,设置scrollCeiling为具体数值时表示从当前距离开始吸顶,设置0表示至始至终吸顶。
- 可通过onMenuChange函数设置菜单打开收起的回调函数。
*
* 主要属性和接口:
* - visible:初始展开或收起的状态, 默认false收起。
* - scrollCeiling:设置吸顶的距离, 默认不吸顶, 设置0表示始终吸顶。
* - onMenuChange:菜单打开关闭时的回调函数。 <br/>
* 如:
* ```code
* <Menu scrollCeiling={100} visible={true} onMenuChange={(visible)=>{console.log(visible);}}>
* <Menu.Header>
* 标题一
* </Menu.Header>
* <Menu.Body>
* ...
* </Menu.Body>
* </Menu>
* ```
*
* @class Menu
* @module 菜单组件
* @extends Component
* @constructor
* @since 1.3.0
* @demo menu|menu.js {展示}
* @show true
* */
class Menu extends Component{
static propTypes = {
/**
* 样式前缀
* @property classPrefix
* @type String
* @default 'menu'
* */
classPrefix: PropTypes.string,
/**
* 标签tagName
* @property componentTag
* @type String
* */
componentTag:PropTypes.string,
/**
* 是否可见标识
* @property visible
* @type Boolean
* @default false
* */
visible: PropTypes.bool,
/**
* 点击收起展开的回调函数
* @method onMenuChange
* @type Function
* */
onMenuChange: PropTypes.func,
/**
* 是否滚动吸顶, 默认不吸顶(false); 设置确定的数字从当前距离开始吸顶
* @property scrollCeiling
* @type Number
* @default 不设置
* */
scrollCeiling: PropTypes.number
};
static defaultProps = {
visible: false,
classPrefix:'menu',
componentTag:'div',
classMapping : {}
};
constructor(props, context) {
super(props, context);
this.handleDocumentClick = this.handleDocumentClick.bind(this);
this.handleWindowScroll = this.handleWindowScroll.bind(this);
this.state = {
visible: props.visible,
ceiling: !(props.scrollCeiling === undefined || props.scrollCeiling > 0),
headerHeight: 0
};
document.addEventListener('click', this.handleDocumentClick, false);
// 是否滚动吸顶
if(props.scrollCeiling === undefined || props.scrollCeiling === 0) return;
window.addEventListener('scroll', this.handleWindowScroll, false);
}
handleDocumentClick(event){
if(!this.state.visible) return;
let el = event.target;
if(!closest(el,'.ph-menu')){
this.setState({
visible: false
}, ()=>{
if(this.props.onMenuChange) this.props.onMenuChange(this.state.visible);
});
}
return false;
}
handleWindowScroll(){
if(document.body.scrollTop >= this.props.scrollCeiling){
if(!this.state.ceiling) this.setState({ceiling: true});
}else{
if(this.state.ceiling) this.setState({ceiling: false});
}
}
componentDidMount(){
setTimeout(()=>{
this.menuPlaceholder.style.height = this.menuCeiling.offsetHeight +'px';
this.setState({headerHeight: this.menuCeiling.offsetHeight})
},0);
}
// componentWillReceiveProps(nextProps){
// if(this.state.visible != nextProps.visible){
// this.setState({
// visible: nextProps.visible
// }, ()=>{
// if(this.props.onMenuChange) this.props.onMenuChange(nextProps.visible);
// });
// }
// }
changeVisible(){
this.setState({
visible: !this.state.visible
}, ()=>{
if(this.props.onMenuChange) this.props.onMenuChange(this.state.visible);
});
}
renderChildren(){
let _this = this;
let newChildren = [];
React.Children.forEach(this.props.children, function(child, index){
newChildren.push(React.cloneElement(child, {
key: index,
visible: _this.state.visible,
changeVisible: _this.changeVisible.bind(_this),
headerHeight: _this.state.headerHeight
}));
});
return newChildren;
}
componentWillUnmount(){
document.removeEventListener('click', this.handleDocumentClick, false);
window.removeEventListener('scroll', this.handleWindowScroll, false);
}
render(){
let {componentTag:Component, className} = this.props;
return (
<Component {...this.props} className={classnames(
this.getProperty(true),
setPhoenixPrefix('menu-placeholder'),
className
)} ref={(menuPlaceholder)=>{this.menuPlaceholder=menuPlaceholder}}>
<div className={this.state.ceiling? setPhoenixPrefix('menu-ceiling'):''} ref={(menuCeiling)=>{this.menuCeiling=menuCeiling}}>
{this.renderChildren()}
</div>
</Component>
);
}
}
Menu.Header = MenuHeader;
Menu.Body = MenuBody;
Menu.Nav = MenuNav;
Menu.List = MenuList;
Menu.Item = MenuItem;
export default Menu;