Skip to content

Commit f97ea4c

Browse files
committed
fix: 修复单击触发bug
1 parent ddb38c9 commit f97ea4c

File tree

6 files changed

+62
-51
lines changed

6 files changed

+62
-51
lines changed

src/ContextMenu/Item.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@ export type ContextMenuItemProps = {
99
curData: React.MutableRefObject<ContextMenuItem | undefined>;
1010
depth: number;
1111
prevRects: Array<() => HTMLUListElement>;
12-
loadding: React.ReactNode
12+
loadding: React.ReactNode;
13+
setMenuVisible: (visible: boolean) => void
1314
}
1415

1516
const Item = memo(function (props: ContextMenuItemProps) { // 渲染单项
16-
const { item, curData, onClick , prevRects, depth, loadding} = props;
17+
const { item, curData, onClick , prevRects, depth, loadding, setMenuVisible} = props;
1718
const [isLoadding, setLoadding] = useState(false)
1819
const [showChildren, setShowChildren] = useState(false)
1920
const [, startTransition] = useTransition()
@@ -27,6 +28,7 @@ const Item = memo(function (props: ContextMenuItemProps) { // 渲染单项
2728
return
2829
}
2930
!item.disabled && onClick(e, curData?.current as any, item)
31+
setMenuVisible(false)
3032
}}
3133
tabIndex={-1}
3234
onMouseEnter={async (e) => {

src/ContextMenu/README.md

+28-23
Original file line numberDiff line numberDiff line change
@@ -103,45 +103,50 @@ export default function MyContextMenu () {
103103
}
104104
```
105105

106-
## 多级菜单 & 异步动态加载
106+
## 多级菜单 & 异步无限加载
107+
108+
用来测试极端情况,始终报纸多层情况下能渲染在可视化屏幕内。
107109

108110
```tsx
109111
import { ContextMenu } from '@vis/components';
110-
import React from 'react'
112+
import React from 'react';
111113
import { ReloadOutlined } from '@ant-design/icons';
112114
const { useContextMenu } = ContextMenu;
113-
114-
export default function MyContextMenu () {
115-
const { Trigger, ContextMenu } = useContextMenu()
116-
117-
118-
return <div>
119-
<Trigger data={{id: '123'}}>右键我</Trigger>
120-
<ContextMenu menus={[{ label: '操作1', value: '1' },
121-
{
122-
label: '动态异步菜单',
123-
value: 'key2',
124-
icon: <ReloadOutlined />,
125-
children: () => {
115+
import { Spin } from 'antd';
116+
const loadChildren = (item) => {
126117
return new Promise((resolve, reject) => {
127118
setTimeout(() => {
128119
resolve([
129-
{ label: '操作2-1',
130-
value: 'key2-1'
120+
{ label: `操作${item.value}-1`,
121+
value: `key${item.value}-1`
131122
},
132-
{ label: '操作2-2',
133-
value: 'key2-2'
123+
{ label: `操作${item.value}-2`,
124+
value: `key${item.value}-2`,
125+
children: loadChildren
134126
},
135-
{ label: '操作2-3',
136-
value: 'key2-3'
127+
{ label: `操作${item.value}-3`,
128+
value: `key${item.value}-3`
137129
},
138-
{ label: '操作2-4',
139-
value: 'key2-4'
130+
{ label: `操作${item.value}-4`,
131+
value: `key${item.value}-4`
140132
}
141133
])
142134
}, 1000)
143135
})
144136
}
137+
export default function MyContextMenu () {
138+
const { Trigger, ContextMenu } = useContextMenu()
139+
140+
return <div>
141+
<Trigger data={{id: '123'}} style={{border: 'solid 1px red'}}><div>右键我</div></Trigger>
142+
<ContextMenu
143+
loadding={<Spin size={'small'}/>}
144+
menus={[{ label: '操作1', value: '1' },
145+
{
146+
label: '动态异步菜单',
147+
value: 'key2',
148+
icon: <ReloadOutlined />,
149+
children: loadChildren
145150
},
146151
]} onClick={(e, data, menu) => {
147152
alert(`data.id: ${data.id} menu.value: ${menu.value}`)

src/ContextMenu/SubMenu.tsx

+13-9
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ declare type SubMenuProps = {
1616

1717
export default function (props : SubMenuProps) {
1818
const { children, prevRects, depth } = props
19-
const [_layout, setLayout] = useState<React.CSSProperties>({ position: 'absolute', left: '100%', top: '0' })
19+
const [_layout, setLayout] = useState<React.CSSProperties>({ position: 'absolute', left: '100%', top: '0', zIndex: depth })
2020
const rectRef = createRef<HTMLUListElement>()
2121
prevRects[depth] = () => rectRef.current as HTMLUListElement
2222
useLayoutEffect(() => {
@@ -26,17 +26,21 @@ export default function (props : SubMenuProps) {
2626
let layout: React.CSSProperties = { transform : ''}
2727
if(res?.right) { // 右侧无法展示, 移到最左侧展示
2828
let moveX = 0
29-
prevRects.forEach((i, idx) => {
30-
if(idx !== prevRects.length -1 ) {
31-
moveX += (i?.()?.getBoundingClientRect().width) || 0
32-
}
33-
})
34-
layout.transform += `translateX(calc( -100% - ${moveX}px ))`
29+
if(depth <= 1) { // 如果当前第二层以前,更好的效果我们渲染到最左边去
30+
prevRects.forEach((i, idx) => {
31+
if(idx !== prevRects.length -1 ) {
32+
moveX += (i?.()?.getBoundingClientRect().width) || 0
33+
}
34+
})
35+
layout.transform += `translateX(calc( -100% - ${moveX}px ))`
36+
}else{ // 否则直接基于上一次的出来的做累加
37+
layout.left = 10
38+
}
3539
}
3640
if(res?.bottom) {
37-
layout.transform += `translateY(-${res.bottom}px )`
41+
layout.transform += `translateY(-${res.bottom as number + depth * 10}px )`
3842
}
39-
setLayout({..._layout, ...layout})
43+
(res?.right || res?.bottom ) && setLayout({..._layout, ...layout})
4044
}, [])
4145
return (
4246
<ul

src/ContextMenu/helper.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export const compareShapeLocation = function (b: DOMRect) {
77
}
88
0 > b.left && (ret.left = true)
99
0 > b.top && (ret.top = true)
10-
window.innerWidth < b.right && (ret.right = true)
10+
window.innerWidth < b.right && (ret.right = b.right - window.innerWidth)
1111
window.innerHeight < (b.bottom ) && (ret.bottom = (b.bottom) - window.innerHeight)
1212
return ret
1313
}

src/ContextMenu/index.tsx

+11-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { MouseEvent } from 'react';
1+
import { MouseEvent, useMemo } from 'react';
22
import './index.less';
33
import Item from './Item';
44
import SubMenu from './SubMenu';
@@ -22,7 +22,7 @@ export declare type ContextMenuItem = {
2222

2323
export type HandleClick = (e: MouseEvent<HTMLLIElement, any>, item: ContextMenuItem & { target: HTMLElement }, menu: ContextMenuItem) => void
2424

25-
type ContextMenuProps = {
25+
export type ContextMenuProps = {
2626
/** 菜单数据 */
2727
menus: Array<ContextMenuItem>;
2828
onClick: HandleClick;
@@ -37,6 +37,8 @@ type ContextMenuProps = {
3737
prevRects?: Array<() => HTMLUListElement>;
3838
/** 自定义加载图表 */
3939
loadding?: React.ReactNode;
40+
/** 设置菜单显示隐藏 */
41+
setMenuVisible: (visible: boolean) => void
4042
};
4143

4244
export const prefixCls = 'vis-comp-context-menu-'
@@ -48,13 +50,14 @@ const ContextMenu = function (props: ContextMenuProps) {
4850
curItem,
4951
prevRects = [],
5052
depth = 0,
51-
loadding
53+
loadding,
54+
setMenuVisible
5255
} = props
53-
return <SubMenu {...props} depth={ depth } prevRects={prevRects}>
54-
{
55-
menus.map(i => <Item loadding={loadding} item={i} curData={ curItem } onClick={onClick} prevRects={prevRects} depth={depth + 1}/>)
56-
}
57-
</SubMenu>
56+
return useMemo(() => <SubMenu {...props} depth={ depth } prevRects={prevRects}>
57+
{
58+
menus.map(i => <Item loadding={loadding} item={i} curData={ curItem } onClick={onClick} prevRects={prevRects} depth={depth + 1} setMenuVisible={setMenuVisible}/>)
59+
}
60+
</SubMenu>, [onClick, menus, loadding])
5861
}
5962

6063
ContextMenu.Item = Item

src/ContextMenu/useContextMenu.tsx

+5-8
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export default (hooksProps : HooksProps) => {
4747
const el = createRef<HTMLDivElement>()
4848
useLayoutEffect(() => {
4949
const contextMenuHandle = function (e: MouseEvent) {
50+
e.stopPropagation()
5051
e.preventDefault()
5152
curItem.current = data
5253
setPosition({
@@ -74,20 +75,15 @@ export default (hooksProps : HooksProps) => {
7475
}: ContextMenuProps) => {
7576
useLayoutEffect(() => {
7677
const hideMenu = function () {
77-
setTimeout(() => {
78-
setMenuVisible(false);
79-
}, 0);
78+
setMenuVisible(false);
8079
}
81-
event !== 'click' && document.body.addEventListener('click', hideMenu)
80+
document.body.addEventListener('click', hideMenu)
8281
return () => {
83-
event !== 'click' && document.body.removeEventListener('click', hideMenu)
82+
document.body.removeEventListener('click', hideMenu)
8483
}
8584
}, [])
8685
return <div
8786
tabIndex={0}
88-
onClick={() => {
89-
setMenuVisible(false)
90-
}}
9187
style={{
9288
left: position.x ?? 0,
9389
top: position.y ?? 0,
@@ -100,6 +96,7 @@ export default (hooksProps : HooksProps) => {
10096
onClick={onClick}
10197
curItem={curItem}
10298
loadding={loadding}
99+
setMenuVisible={setMenuVisible}
103100
/>
104101
</div>
105102
}

0 commit comments

Comments
 (0)