lm-tab
Version:
* 作者:winber * 邮箱:winberxie@163.com * 版本:**`0.4.0`**
266 lines (229 loc) • 7.25 kB
JavaScript
/**
* Created by winber<winberxie@163.com>.
* ComponentName Tab
* Desc 组件描述内容
* GroupName lm-component
*/
import React from 'react'
import PropTypes from 'prop-types';
import classNames from 'classnames';
import './index.scss';
export const NavBar = (props) => {
const {className, children, ...others} = props;
const cls = classNames({
'lm-nav-bar': true
}, className);
return (
<div className={cls} {...others}>
{children}
</div>
)
}
export const NavBarItem = (props) => {
const {className, label, active, children, ...others} = props;
const cls = classNames({
'lm-nav-bar-item': true,
'lm-nav-bar-active': active
}, className);
return (
<div className={cls} {...others}>
{label ? label : children}
</div>
)
}
NavBarItem.propTypes = {
active: PropTypes.bool,
label: PropTypes.string,
};
export const TabBar = (props) => {
const {className, children, ...others} = props;
const cls = classNames({
'lm-tab-bar': true
}, className);
return (
<div className={cls} {...others}>
{children}
</div>
)
}
/**
* TabBarItem 组件
* @param {object} props --属性对象
* @enum {string} desc 文本描述
* @enum {base64} activeIcon 选中时对应的icon
* @enum {base64} icon 未选中时对应的icon
* @enum {boolean} active 当前是否选中 true:选中 false:未选中
* @return {[React.Element]} 组件需要渲染的dom
*/
export const TabBarItem = (props) => {
const {className, desc, active, activeIcon, icon, ...others} = props;
const cls = classNames({
'lm-tab-bar-item': true,
'lm-tab-bar-active': active
}, className);
return (
<div className={cls} {...others}>
<img alt="" className='lm-tab-bar-icon' src={active ? activeIcon : icon}/>
<p>{desc}</p>
</div>
)
}
TabBarItem.propTypes = {
active: PropTypes.bool,
activeIcon: PropTypes.any.isRequired,
icon: PropTypes.any.isRequired,
desc: PropTypes.string.isRequired
};
export const TabBody = (props) => {
const {children, ...others} = props;
return (
<div {...others}>
{children}
</div>
)
}
/**
* TabBarItem 组件
* @param {object} props --属性对象
* @enum {boolean} active 当前是否选中 true:选中 false:未选中
* @return {[React.Element]} 组件需要渲染的dom
*/
export const TabBodyItem = (props) => {
const {children, active, className, ...others} = props;
const cls = classNames({
'lm-tab-body-item': true,
'lm-tab-body-item-active': active
}, className);
return (
<div className={cls}
{...others}
>
{children}
</div>
)
}
export class Tab extends React.Component {
constructor(props){
super(props);
this.state = {
/**
* @description - 所选中的tabItem的索引
* @property {number} index 当前所选中的tabItem的索引
*/
index: this.props.defaultIndex
}
};
static defaultProps = {
type: 'normal',
defaultIndex: 0,
};
static propTypes = {
type: PropTypes.string,
onChange: PropTypes.func,
defaultIndex: PropTypes.number
};
/**
* 点击tabItem的回调函数
* @param {number} index --当前所选中的tab索引
*/
handleHeaderClick = (index) => {
const prevIndex = this.state.index;
this.setState({index},() => {
this.props.onChange && prevIndex !== index && this.props.onChange(index);
});
};
/**
* 提取contentItem & navItem & 属性
* @param {React.Element} childrenInput --Tab 组件的childen
* @return {object} --navbar的items & tabBody的items & navbar的props &tabBody的props
*/
parseChild(children) {
//缓存navbar的items
const ChildHeaders = [];
//缓存tabBody的items
const ChildContents = [];
//缓存tabBody & bar的 props
let tBodyProps, barProps;
React.Children.map(children, child => {
if (!child) return;
const {children} = child.props;
if (child.type === TabBarItem || child.type === NavBarItem){
ChildHeaders.push(child);
if (children) ChildContents.push(<TabBodyItem children={children}/>);
}
if (child.type === TabBodyItem){
ChildContents.push(child);
}
if (child.type === NavBar || child.type === TabBar){
barProps = child.props;
React.Children.map(child.props.children, item => {
ChildHeaders.push(item);
})
}
if (child.type === TabBody){
tBodyProps = child.props;
React.Children.map(child.props.children, item => {
ChildContents.push(item);
})
}
});
return {ChildHeaders, ChildContents, tBodyProps, barProps};
};
/**
* Tab需要render的内容
* @param {string} type --Tab组件的类型
* @param {React.Element} children -Tab组件的children
* @param {object} props --Tab组件自定义的样式
* @return {React.Element} --Tab需要render的内容
*/
renderBar(type, children, props) {
const {ChildHeaders, ChildContents, tBodyProps, barProps} = this.parseChild(children);
let _headers = ChildHeaders.map((item, idx)=>{
const { onClick, active, ...others }= item.props
return React.cloneElement(item, {
key: idx,
active: this.state.index === idx,
onClick: (e) => {
onClick && onClick(e);
this.handleHeaderClick(idx);
},
...others
});
});
let _contents = ChildContents.map((item, idx)=>{
return React.cloneElement(item, {
key: idx,
active: this.state.index === idx
});
});
if (type === 'tabBar'){
return (
<div {...props}>
<TabBody {...tBodyProps}>
{_contents}
</TabBody>
<TabBar {...barProps}>
{_headers}
</TabBar>
</div>
);
}
if (type === 'navBar' || 'normal'){
return (
<div {...props}>
<NavBar {...barProps}>
{_headers}
</NavBar>
<TabBody {...tBodyProps}>
{_contents}
</TabBody>
</div>
);
}
return false;
}
render() {
const {children, type, defaultIndex, ...others} = this.props;
return this.renderBar(type, children, others);
}
}