refactor(right-key): move interaction logic to component and trigger on mouseup

This commit is contained in:
yuding
2025-12-10 10:10:09 +08:00
parent 1f27d02788
commit ef79b5b370
3 changed files with 62 additions and 14 deletions

View File

@@ -13,8 +13,13 @@ export class BimRightKey implements IBimComponent {
private content: IRightKeyContent | null = null; private content: IRightKeyContent | null = null;
private isVisible: boolean = false; private isVisible: boolean = false;
private onCloseCallback?: () => void; private onCloseCallback?: () => void;
private options?: RightKeyOptions;
private mouseDownTime: number = 0;
private readonly CLICK_THRESHOLD: number = 200; // ms
constructor(options?: RightKeyOptions) { constructor(options?: RightKeyOptions) {
this.options = options;
this.element = document.createElement('div'); this.element = document.createElement('div');
this.element.className = `bim-right-key ${options?.className || ''}`; this.element.className = `bim-right-key ${options?.className || ''}`;
@@ -36,6 +41,13 @@ export class BimRightKey implements IBimComponent {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
}); });
// 绑定容器交互事件
if (this.options?.container) {
this.options.container.addEventListener('mousedown', this.handleContainerMouseDown);
this.options.container.addEventListener('mouseup', this.handleContainerMouseUp);
this.options.container.addEventListener('contextmenu', this.handleContainerContextMenu);
}
} }
public setTheme(_theme: ThemeConfig): void { public setTheme(_theme: ThemeConfig): void {
@@ -51,10 +63,46 @@ export class BimRightKey implements IBimComponent {
public destroy(): void { public destroy(): void {
document.removeEventListener('mousedown', this.handleGlobalClick); document.removeEventListener('mousedown', this.handleGlobalClick);
if (this.options?.container) {
this.options.container.removeEventListener('mousedown', this.handleContainerMouseDown);
this.options.container.removeEventListener('mouseup', this.handleContainerMouseUp);
this.options.container.removeEventListener('contextmenu', this.handleContainerContextMenu);
}
this.unmountContent(); this.unmountContent();
this.element.remove(); this.element.remove();
} }
private handleContainerMouseDown = (e: MouseEvent): void => {
// 记录右键按下时间 (button 2 是右键)
if (e.button === 2) {
this.mouseDownTime = Date.now();
}
};
private handleContainerMouseUp = (e: MouseEvent): void => {
// 只处理右键 (button 2)
if (e.button !== 2) return;
// 检查点击时长,如果是长按或拖拽(时间过长),则不触发回调
const pressDuration = Date.now() - this.mouseDownTime;
if (pressDuration > this.CLICK_THRESHOLD) {
return;
}
// 触发有效右键回调
if (this.options?.onContext) {
this.options.onContext(e);
}
};
private handleContainerContextMenu = (e: MouseEvent): void => {
// 阻止浏览器默认的右键菜单
// 真正的菜单触发逻辑已移至 mouseup这里只负责拦截默认行为
e.preventDefault();
};
/** /**
* 设置关闭时的回调函数 * 设置关闭时的回调函数
* 通常用于通知 Manager 状态变更 * 通常用于通知 Manager 状态变更
@@ -80,7 +128,7 @@ export class BimRightKey implements IBimComponent {
*/ */
public unmountContent(): void { public unmountContent(): void {
if (this.content) { if (this.content) {
this.content.destroy(); // 重要:调用组件销毁方法清理 this.content.destroy(); // 重要:调用组件销毁方法清理<EFBFBD><EFBFBD><EFBFBD>
this.element.innerHTML = ''; this.element.innerHTML = '';
this.content = null; this.content = null;
} }
@@ -100,7 +148,7 @@ export class BimRightKey implements IBimComponent {
this.element.style.left = `${x}px`; this.element.style.left = `${x}px`;
this.element.style.top = `${y}px`; this.element.style.top = `${y}px`;
// 2. 获取容器<EFBFBD><EFBFBD><EFBFBD>寸和视口尺寸 // 2. 获取容器寸和视口尺寸
const rect = this.element.getBoundingClientRect(); const rect = this.element.getBoundingClientRect();
const viewportWidth = window.innerWidth; const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight; const viewportHeight = window.innerHeight;

View File

@@ -15,4 +15,8 @@ export interface RightKeyOptions {
className?: string; className?: string;
/** 层级 (z-index) */ /** 层级 (z-index) */
zIndex?: number; zIndex?: number;
/** 监听事件的容器 */
container?: HTMLElement;
/** 有效右键点击时的回调 */
onContext?: (e: MouseEvent) => void;
} }

View File

@@ -16,7 +16,7 @@ export class RightKeyManager extends BimComponent {
private rightKeyPanel: BimRightKey; private rightKeyPanel: BimRightKey;
// 存储注册的上下文处理器 // 存储注册的上下文处理器
// 每个处理<EFBFBD><EFBFBD>接收鼠标事件,返回一组菜单项(如果没有对应菜单则返回 null // 每个处理接收鼠标事件,返回一组菜单项(如果没有对应菜单则返回 null
private contextHandlers: Array<(e: MouseEvent) => MenuItemConfig[] | null> = []; private contextHandlers: Array<(e: MouseEvent) => MenuItemConfig[] | null> = [];
constructor(engine: BimEngine, container: HTMLElement) { constructor(engine: BimEngine, container: HTMLElement) {
@@ -24,18 +24,16 @@ export class RightKeyManager extends BimComponent {
this.container = container; this.container = container;
// 初始化右键容器,设置极高的层级以覆盖所有 UI // 初始化右键容器,设置极高的层级以覆盖所有 UI
this.rightKeyPanel = new BimRightKey({ zIndex: 9000 }); // 将事件监听和触发逻辑下放给 BimRightKey 组件
this.rightKeyPanel = new BimRightKey({
zIndex: 9000,
container: this.container,
onContext: this.handleContextMenu
});
this.rightKeyPanel.init(); this.rightKeyPanel.init();
this.initEventListeners();
}
private initEventListeners(): void {
this.container.addEventListener('contextmenu', this.handleContextMenu);
} }
public destroy(): void { public destroy(): void {
this.container.removeEventListener('contextmenu', this.handleContextMenu);
this.rightKeyPanel.destroy(); this.rightKeyPanel.destroy();
} }
@@ -78,11 +76,9 @@ export class RightKeyManager extends BimComponent {
/** /**
* 处理右键点击事件 * 处理右键点击事件
* 由 BimRightKey 组件在检测到有效右键点击时调用
*/ */
private handleContextMenu = (e: MouseEvent): void => { private handleContextMenu = (e: MouseEvent): void => {
// 阻止浏览器默认的右键菜单
e.preventDefault();
// 1. 确定上下文项 // 1. 确定上下文项
// 遍历所有注册的处理器,找到第一个返回非空结果的处理器 // 遍历所有注册的处理器,找到第一个返回非空结果的处理器
// 这种责任链模式允许插件优先处理特定对象的右键 // 这种责任链模式允许插件优先处理特定对象的右键