UNPKG

zarm-web

Version:
301 lines (264 loc) 7.19 kB
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } import React, { Component, Children, cloneElement } from 'react'; import classnames from 'classnames'; import dom from '../utils/dom'; import events from '../utils/events'; import MenuContext from './menu-context'; export class SubMenu extends Component { constructor(props) { super(props); this.subTitle = void 0; this.sub = void 0; this.timeout = void 0; this.toggleSubMenuOpen = e => { e.stopPropagation(); const { subMenuKey } = this.props; this.props.toggleOpenKeys(subMenuKey); }; this.onSubAnimationEnd = () => { const { subMenuKey, openKeys } = this.props; const isOpen = openKeys.indexOf(subMenuKey) > -1; this.setState({ collapsedSubVisible: isOpen }); }; this.onClickOutSide = e => { const { target } = e; const { subMenuKey, openKeys } = this.props; if (this.subTitle.contains(target)) { return; } if (!this.sub.contains(target) && openKeys.indexOf(subMenuKey) > -1) { this.props.toggleOpenKeys(subMenuKey); } }; this.state = { collapsedSubVisible: false, collapsedSubAnimation: '' }; } componentDidMount() { const { openKeys, inlineCollapsed } = this.props; if (openKeys.length > 0) { if (!inlineCollapsed) { this.setSubHeight({ openKeys: [] }); } } if (inlineCollapsed) { events.on(document, 'click', this.onClickOutSide); } } componentWillReceiveProps(nextProps) { const { inlineCollapsed } = nextProps; if (!inlineCollapsed) { // eslint-disable-next-line react/destructuring-assignment if (this.props.inlineCollapsed) { events.off(document, 'click', this.onClickOutSide); } return; } // eslint-disable-next-line react/destructuring-assignment if (!this.props.inlineCollapsed) { events.on(document, 'click', this.onClickOutSide); } const { subMenuKey, openKeys } = this.props; const isOpenNow = openKeys.indexOf(subMenuKey) > -1; const isOpenNext = nextProps.openKeys.indexOf(subMenuKey) > -1; if (!isOpenNow && isOpenNext) { // 展开菜单 this.slideDown(); } else if (isOpenNow && !isOpenNext) { // 收起菜单 this.slideUp(); } } componentDidUpdate(prevProps) { const { inlineCollapsed } = this.props; if (!inlineCollapsed) { this.setSubHeight(prevProps); } } componentWillUnmount() { const { inlineCollapsed } = this.props; if (inlineCollapsed) { events.off(document, 'click', this.onClickOutSide); } } getSubHeight() { if (!this.sub) { return; } const childs = [...this.sub.children]; let marginBottom = 0; if (childs[0]) { marginBottom = parseFloat(dom.getStyleComputedProperty(childs[0], 'marginBottom')); } const height = childs.reduce((res, next) => { res += next.offsetHeight + marginBottom; return res; }, marginBottom / 2); return height; } setSubHeight(prevProps) { if (!this.sub) { return; } const { openKeys: lastOpenKeys } = prevProps; const { openKeys, subMenuKey } = this.props; const keyIndex = openKeys.indexOf(subMenuKey); const keysLength = openKeys.length; if (keyIndex > -1) { if (keysLength > 1 && keyIndex < keysLength - 1 || keysLength < lastOpenKeys.length) { // 如果不是最后一级子菜单,或者嵌套的子菜单被收起,当前子菜单高度自适应 this.sub.style.height = 'auto'; } else { // 否则,设置具体的高度产生过渡动画 const height = this.getSubHeight(); this.sub.style.height = `${height}px`; } } else { const height = this.getSubHeight(); this.sub.style.height = `${height}px`; setTimeout(() => { this.sub.style.height = 0; }, 0); } } slideUp() { this.setState({ collapsedSubVisible: false, collapsedSubAnimation: 'up' }); } slideDown() { this.setState({ collapsedSubVisible: true, collapsedSubAnimation: 'down' }); } renderChildren() { const { children, level, inlineIndent, mode, prefixCls, subMenuKey } = this.props; const childProps = { mode, level: level + 1, inlineIndent, prefixCls }; return Children.map(children, (child, index) => { const c = child; const { key } = child; childProps.itemKey = key || `${subMenuKey}-${level}-${index}`; childProps.subMenuKey = key || `${subMenuKey}-${level}-${index}`; return cloneElement(c, childProps); }); } render() { const { title, level, mode, style, inlineIndent, prefixCls, openKeys, subMenuKey, inlineCollapsed } = this.props; const { collapsedSubVisible, collapsedSubAnimation } = this.state; const subMenuStyle = {}; if (mode === 'inline' && !inlineCollapsed) { subMenuStyle.paddingLeft = level * inlineIndent; } const isOpen = openKeys.indexOf(subMenuKey) > -1; const cls = classnames(`${prefixCls}-submenu`, { open: isOpen, [`${prefixCls}-level-${level}`]: level }); let subStyle = { display: 'block' }; let subCls = `${prefixCls}-submenu-sub`; if (inlineCollapsed) { subStyle = { display: collapsedSubVisible ? 'block' : 'none' }; subCls = classnames(`${prefixCls}`, `${prefixCls}-submenu-sub`, { [`slide-${collapsedSubAnimation}`]: !!collapsedSubAnimation }); } return React.createElement("li", { className: cls, style: style }, React.createElement("div", { ref: subTitle => { this.subTitle = subTitle; }, onClick: this.toggleSubMenuOpen, style: subMenuStyle, className: `${prefixCls}-submenu-title` }, title, React.createElement("i", { className: `${prefixCls}-submenu-arrow` })), React.createElement("ul", { ref: sub => { this.sub = sub; }, className: subCls, style: subStyle, onAnimationEnd: this.onSubAnimationEnd }, this.renderChildren())); } } SubMenu.defaultProps = { prefixCls: 'za-menu', title: '', level: 1, style: {}, openKeys: [] }; export default function SubMenuConsumer(props) { return React.createElement(MenuContext.Consumer, null, menuKeys => React.createElement(SubMenu, _extends({}, props, { inlineCollapsed: menuKeys.inlineCollapsed, openKeys: menuKeys.openKeys, toggleOpenKeys: menuKeys.toggleOpenKeys }))); }