src/Tabs.js
/**
* @file melon/Tabs
* @author cxtom<[email protected]>
*/
import React, {Component, PropTypes, cloneElement, Children} from 'react';
import Tab from './tabs/Tab';
import TabPanel from './tabs/Panel';
import {create} from 'melon-core/classname/cxBuilder';
const cx = create('Tabs');
/**
* melon/Tabs
*
* @class
*/
export default class Tabs extends Component {
/**
* 构造函数
*
* @public
* @constructor
* @param {*} props 属性
*/
constructor(props) {
super(props);
const selectedIndex = props.selectedIndex;
/**
* 状态
*
* @private
* @type {Object}
*/
this.state = {
selectedIndex
};
}
/**
* 接受新属性时的处理
*
* @public
* @override
* @param {*} nextProps 新属性
*/
componentWillReceiveProps(nextProps) {
if (nextProps.selectedIndex !== this.state.selectedIndex) {
this.setState({
selectedIndex: nextProps.selectedIndex
});
}
}
/**
* 处理 Tab 点击事件
*
* @private
* @param {number} index tab 序号
* @param {e} e 原始点击事件
*/
handleTabClick(index, e) {
if (index === this.state.selectedIndex) {
return;
}
let {onBeforeChange, onChange} = this.props;
e.selectedIndex = index;
if (onBeforeChange) {
onBeforeChange(e);
if (e.isDefaultPrevented()) {
return;
}
}
this.setState({selectedIndex: index}, function () {
onChange && onChange(e);
});
}
/**
* 获取 Tab 总数
*
* @protected
* @return {number}
*/
getTabCount() {
return Children.count(this.props.children);
}
/**
* 指定序号的标签是否被选中
*
* @protected
* @param {number} index 序号
* @return {boolean}
*/
isTabSelected(index) {
return this.state.selectedIndex === index;
}
/**
* 渲染
*
* @public
* @return {ReactElement}
*/
render() {
const props = this.props;
let tabIndex = 0;
const percent = 1 / this.getTabCount() * 100 + '%';
const tabContents = [];
const tabs = [];
const children = Children.toArray(props.children);
for (let i = 0, len = children.length; i < len; ++i) {
let tab = children[i];
const selected = this.isTabSelected(i);
if (selected) {
tabIndex = i;
}
if (children) {
tabContents.push(
<TabPanel key={i} active={selected}>
{tab.props.children}
</TabPanel>
);
}
tabs.push(cloneElement(tab, {
key: i,
selected: selected,
tabIndex: i,
style: {width: percent},
onClick: tab.props.disabled ? null : this.handleTabClick.bind(this, i)
}));
}
const InkBarStyles = {
width: percent,
left: 'calc(' + percent + '*' + tabIndex + ')'
};
return (
<div {...props} className={cx(props).build()}>
<ul>
{tabs}
<li className={cx().part('inkbar').build()} style={InkBarStyles}></li>
</ul>
{tabContents}
</div>
);
}
}
/**
* propTypes
*
* @property {number} selectedIndex 选中标签的序号
* @property {Function} onChange 选中标签发生变化后处理函数
* @property {Function} onBeforeChange 选中标签发生变化前处理函数
*/
Tabs.propTypes = {
selectedIndex: PropTypes.number.isRequired,
onChange: PropTypes.func,
onBeforeChange: PropTypes.func
};
Tabs.defaultProps = {
selectedIndex: 0
};
Tabs.Tab = Tab;