普通模式
手风琴模式
第一:菜单基本使用
const MenuUse = () => {
const items: MenuItem[] = [
getItem('Navigation One', 'sub1', <MailOutlined />, [
getItem('Item 1', 'g1', null),
getItem('Item 2', 'g2', null),
]),
getItem('Navigation Two', 'sub2', <AppstoreOutlined />, []),
getItem('Navigation Three', 'sub4', <SettingOutlined />, [
getItem('Option 9', '9', null, [
getItem('Item 1', 'g14', null),
getItem('Item 2', 'g25', null),
]),
getItem('Option 10', '10'),
]),
];
return <Menu items={items} ableToggle={true} curSelectKey={'sub2'} />;
};
菜单的基本 HTML 结构实现
菜单的展开和收缩基本思路
通过使用 ref,获取到对应收缩子容器的节点。
实现树的展开和收缩
第一:收缩的时候,高度变为 0 + 过渡动画
第二:扩张的时候,高度变为本来容器的高度 + 过渡动画
这里有个细节大家要注意:扩张结束之后,高度应该设为 auto, 不设 auto,树展开的高度计算就会有偏差,导致出现 UI bug。
const transitionCallback = (callback: callback) => () => {
callback(wrapperRef.current, heightRef);
};
const handleOnEnter = transitionCallback((node: HTMLElement) => {
node.style['height'] = collapsedSize + 'px';
});
const handleEntering = transitionCallback((node: HTMLElement) => {
node.style['height'] = heightRef.current;
});
const handelEntered = transitionCallback(
(node: HTMLElement, heightRef: React.MutableRefObject<string>) => {
node.style['height'] = 'auto';
heightRef.current = getWrapperHeight();
},
);
const handleOnExit = transitionCallback(
(node: HTMLElement, heightRef: React.MutableRefObject<string>) => {
const height = node.clientHeight + 'px';
node.style['height'] = height;
if (!heightRef.current) {
heightRef.current = height;
}
},
);
const handleOnExiting = transitionCallback((node: HTMLElement) => {
wrapperRef.current.style['height'] = 0;
});
实现手风琴思路
比方说,点击了第一个菜单的三级导航 1-1-1,那么除了第一个菜单的三级导航及其父元素不改变状态(1,1-1,1-1-1),其余的导航 expand 属性都变为 false -- 收缩,即实现手风琴。
//儿元素 和 其父元素 key的映射表。
const map = getParentKey(props.items);
// 当前点击元素 key 和 其所有父元素 key 的集合
const memoParent = useMemo(() => {
const parent = [];
const getParent = (key: React.Key): React.Key | null => map.get(key);
parent.push(MenuKeys.selectKey);
let p = getParent(MenuKeys.selectKey);
while (p) {
parent.push(p);
p = getParent(p);
}
return parent;
}, [MenuKeys.selectKey]);
其余关键代码 -- HTML 结构
<MenuNode
memoParent={memoParent}
key={c.key}
refContainer={ref}
level={level}
menuItem={c}
isToggle={props.ableToggle}
selectKey={MenuKeys.selectKey}
curToggleKey={MenuKeys.curExpandKey}
clickSelectMenu={clickSelectMenu}
recursive={recursive}
>
<MenuItemContainer
onClick={(e) => clickSelectMenu(c.key, e)}
curKey={c.key}
selectKey={selectKey}
>
<FirstMenuItemContainer>
</FirstMenuItemContainer>
</MenuItemContainer>
<ChildMenu ref={refContainer}>{c.children && recursive(c.children, level + 1)}</ChildMenu>
<MenuNode/>
自此导航菜单实现完成