增强GroupContextMenu和VirtualContactList组件:在GroupContextMenu中添加遮罩层右键事件回调以支持菜单在新位置打开,优化SidebarMenu中的右键菜单逻辑以避免闪烁,提升用户体验。
This commit is contained in:
@@ -162,15 +162,120 @@ const ContactListSimple: React.FC<WechatFriendsProps> = ({
|
||||
(e: React.MouseEvent, group: ContactGroup) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setGroupContextMenu({
|
||||
visible: true,
|
||||
x: e.clientX,
|
||||
y: e.clientY,
|
||||
group,
|
||||
groupType: group.groupType,
|
||||
});
|
||||
|
||||
// 如果已经有菜单打开,先关闭它,然后在下一个渲染周期打开新菜单
|
||||
if (groupContextMenu.visible) {
|
||||
setGroupContextMenu({
|
||||
visible: false,
|
||||
x: 0,
|
||||
y: 0,
|
||||
});
|
||||
// 使用 requestAnimationFrame 确保关闭操作先执行,然后再打开新菜单
|
||||
// 这样可以避免菜单闪烁,提供更流畅的体验
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
setGroupContextMenu({
|
||||
visible: true,
|
||||
x: e.clientX,
|
||||
y: e.clientY,
|
||||
group,
|
||||
groupType: group.groupType,
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// 如果没有菜单打开,直接打开新菜单
|
||||
setGroupContextMenu({
|
||||
visible: true,
|
||||
x: e.clientX,
|
||||
y: e.clientY,
|
||||
group,
|
||||
groupType: group.groupType,
|
||||
});
|
||||
}
|
||||
},
|
||||
[],
|
||||
[groupContextMenu.visible],
|
||||
);
|
||||
|
||||
// 处理遮罩层右键事件:根据鼠标位置找到对应的群组并打开菜单
|
||||
const handleOverlayContextMenu = useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
// 菜单已经关闭,现在需要找到鼠标位置下的群组元素
|
||||
// 使用 setTimeout 确保遮罩层已经移除,DOM 更新完成
|
||||
setTimeout(() => {
|
||||
// 获取当前要显示的群组列表(优先使用新架构的groups)
|
||||
const currentDisplayGroups =
|
||||
newGroups.length > 0
|
||||
? newGroups
|
||||
: contactGroups.map((g: ContactGroupByLabel) => ({
|
||||
id: g.id,
|
||||
groupName: g.groupName,
|
||||
groupType: g.groupType as 1 | 2,
|
||||
count: g.count,
|
||||
sort: g.sort,
|
||||
groupMemo: g.groupMemo,
|
||||
}));
|
||||
|
||||
// 方法1:尝试通过 data-group-key 属性直接找到群组元素
|
||||
const element = document.elementFromPoint(e.clientX, e.clientY);
|
||||
if (!element) return;
|
||||
|
||||
// 向上查找群组头部元素
|
||||
let groupElement: HTMLElement | null = element as HTMLElement;
|
||||
while (groupElement) {
|
||||
// 检查是否有 data-group-key 属性
|
||||
const groupKey = groupElement.getAttribute('data-group-key');
|
||||
if (groupKey) {
|
||||
// 解析 groupKey 获取群组信息
|
||||
const [groupId, groupType] = groupKey.split('_').map(Number);
|
||||
const group = currentDisplayGroups.find(
|
||||
g => g.id === groupId && g.groupType === groupType
|
||||
);
|
||||
if (group) {
|
||||
// 创建合成事件并触发群组右键菜单
|
||||
const syntheticEvent = {
|
||||
...e,
|
||||
preventDefault: () => {},
|
||||
stopPropagation: () => {},
|
||||
clientX: e.clientX,
|
||||
clientY: e.clientY,
|
||||
} as React.MouseEvent;
|
||||
handleGroupContextMenu(syntheticEvent, group);
|
||||
return;
|
||||
}
|
||||
}
|
||||
groupElement = groupElement.parentElement;
|
||||
}
|
||||
|
||||
// 方法2:如果方法1失败,遍历所有群组,检查鼠标位置是否在群组头部范围内
|
||||
for (const group of currentDisplayGroups) {
|
||||
const groupKey = getGroupKey(group.id, group.groupType, selectedAccountId);
|
||||
const groupHeaderElement = document.querySelector(
|
||||
`[data-group-key="${groupKey}"]`
|
||||
) as HTMLElement;
|
||||
if (groupHeaderElement) {
|
||||
const rect = groupHeaderElement.getBoundingClientRect();
|
||||
if (
|
||||
e.clientX >= rect.left &&
|
||||
e.clientX <= rect.right &&
|
||||
e.clientY >= rect.top &&
|
||||
e.clientY <= rect.bottom
|
||||
) {
|
||||
const syntheticEvent = {
|
||||
...e,
|
||||
preventDefault: () => {},
|
||||
stopPropagation: () => {},
|
||||
clientX: e.clientX,
|
||||
clientY: e.clientY,
|
||||
} as React.MouseEvent;
|
||||
handleGroupContextMenu(syntheticEvent, group);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 50); // 给足够的时间让遮罩层移除
|
||||
},
|
||||
[newGroups, contactGroups, selectedAccountId, getGroupKey, handleGroupContextMenu],
|
||||
);
|
||||
|
||||
// 打开新增分组弹窗
|
||||
@@ -666,6 +771,7 @@ const ContactListSimple: React.FC<WechatFriendsProps> = ({
|
||||
onAddClick={handleOpenAddGroupModal}
|
||||
onEditClick={handleOpenEditGroupModal}
|
||||
onDeleteClick={handleOpenDeleteGroupModal}
|
||||
onOverlayContextMenu={handleOverlayContextMenu}
|
||||
/>
|
||||
|
||||
{/* 联系人右键菜单 */}
|
||||
|
||||
Reference in New Issue
Block a user