jc-biz-components
Version:
jc component library based on Antd
236 lines (229 loc) • 5.93 kB
JavaScript
import React, { PureComponent } from 'react'
import { Layout, Menu } from 'antd'
import { Link } from 'react-router-dom'
// import styles from './index.less'
import storage from '../_utils/storage'
const { Sider } = Layout
const { SubMenu } = Menu
const prefixCls = 'jc-sider-menu'
// Allow menu.js config icon as string or ReactNode
// icon: 'setting',
// icon: 'http://demo.com/icon.png',
// icon: <Icon type='setting' />,
const getIcon = (icon) => {
if (typeof icon === 'string' && icon.indexOf('http') === 0) {
return (
<img
src={icon}
alt='icon'
className={`${prefixCls}-icon`}
/>
)
}
if (typeof icon === 'string') {
return (
<span
className={`iconfont ${icon}`}
style={{ marginRight: '35px' }}
/>
)
}
return icon
}
export default class SiderMenu extends PureComponent {
constructor(props) {
super(props)
this.state = {
menus: props.menuData,
openKeys: storage.get('openKeys') || []
}
}
componentWillReceiveProps(nextProps) {
if (nextProps.menuData !== this.state.menus) {
this.setState({
menus: nextProps.menuData
})
}
}
getFlatMenuKeys(menus) {
let keys = []
menus.forEach((item) => {
if (item.children) {
keys.push(item.path)
keys = keys.concat(this.getFlatMenuKeys(item.children))
} else {
keys.push(item.path)
}
})
return keys
}
getSelectedMenuKeys = (path) => {
const flatMenuKeys = this.getFlatMenuKeys(this.state.menus)
const menu = flatMenuKeys.filter(item => path.startsWith(item))
if (menu.length === 1) {
return menu
} else if (menu.length > 1) {
return menu.filter(item => item !== '/')
}
return []
}
/**
* 判断是否是http链接.返回 Link 或 a
* Judge whether it is http link.return a or Link
* @memberof SiderMenu
*/
getMenuItemPath = (item) => {
const itemPath = this.conversionPath(item.path)
const icon = getIcon(item.icon)
const { target, name } = item
// Is it a http link
if (/^https?:\/\//.test(itemPath)) {
return (
<a
href={itemPath}
target={target}
>
{icon}<span>{name}</span>
</a>
)
}
return (
<Link
to={itemPath}
target={target}
replace={itemPath === this.props.location.pathname}
onClick={this.props.isMobile ? () => { this.props.onCollapse(true) } : undefined}
>
{
icon ? (
<span>{icon}<span>{name}</span></span>
) : (
<span style={{ marginLeft: 20 }}>{name}</span>
)
}
</Link>
)
}
/**
* get SubMenu or Item
*/
getSubMenuOrItem=(item) => {
if (item.children && item.children.some(child => child.name)) {
return (
<SubMenu
title={
item.icon ? (
<span>
{getIcon(item.icon)}
<span>{item.name}</span>
</span>
) : item.name
}
key={item.key || item.path}
>
{this.getNavMenuItems(item.children)}
</SubMenu>
)
} else {
return (
<Menu.Item key={item.key || item.path}>
{this.getMenuItemPath(item)}
</Menu.Item>
)
}
}
/**
* 获得菜单子节点
* @memberof SiderMenu
*/
getNavMenuItems = (menusData) => {
if (!menusData) {
return []
}
return menusData
.filter(item => item.name && !item.hideInMenu)
.map((item) => {
const ItemDom = this.getSubMenuOrItem(item)
return this.checkPermissionItem(item.authority, ItemDom)
})
.filter(item => !!item)
}
// conversion Path
// 转化路径
conversionPath=(path) => {
if (path && path.indexOf('http') === 0) {
return path
} else {
return `/${path || ''}`.replace(/\/+/g, '/')
}
}
// permission to check
checkPermissionItem = (authority, ItemDom) => {
if (this.props.Authorized && this.props.Authorized.check) {
const { check } = this.props.Authorized
return check(
authority,
ItemDom
)
}
return ItemDom
}
handleOpenChange = (openKeys) => {
const lastOpenKey = openKeys[openKeys.length - 1]
const isMainMenu = this.state.menus.some(
item => lastOpenKey && (item.key === lastOpenKey || item.path === lastOpenKey)
)
storage.set('openKeys', isMainMenu ? [lastOpenKey] : [...openKeys])
this.setState({
openKeys: isMainMenu ? [lastOpenKey] : [...openKeys],
})
}
render() {
const { logo, collapsed, location: { pathname }, onCollapse, title } = this.props
const { openKeys } = this.state
// Don't show popup menu when it is been collapsed
const menuProps = collapsed ? {} : {
openKeys,
}
// if pathname can't match, use the nearest parent's key
let selectedKeys = this.getSelectedMenuKeys(pathname)
if (!selectedKeys.length) {
selectedKeys = [openKeys[openKeys.length - 1]]
}
return (
<Sider
trigger={null}
collapsible
collapsed={collapsed}
breakpoint='md'
onCollapse={onCollapse}
width={256}
className={`${prefixCls}-sider`}
>
<div
className={`${prefixCls}-logo`}
key='logo'
>
<Link to='/'>
<img
src={logo}
alt='logo'
/>
<h1>{title}</h1>
</Link>
</div>
<Menu
key='Menu'
theme='dark'
mode='inline'
{...menuProps}
onOpenChange={this.handleOpenChange}
selectedKeys={selectedKeys}
style={{ padding: '16px 0', width: '100%' }}
>
{this.getNavMenuItems(this.state.menus)}
</Menu>
</Sider>
)
}
}