From 03352053aecd8a0e8908534aac39bb209abfaff9 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Mon, 9 Mar 2026 22:11:38 +0800 Subject: [PATCH] :recycle: https://github.com/siyuan-note/siyuan/pull/15401 --- app/src/menus/Menu.ts | 30 ++++++++++------------- app/src/util/setPosition.ts | 48 ++++++++++++++----------------------- 2 files changed, 30 insertions(+), 48 deletions(-) diff --git a/app/src/menus/Menu.ts b/app/src/menus/Menu.ts index cd94ac407..f66f2bf84 100644 --- a/app/src/menus/Menu.ts +++ b/app/src/menus/Menu.ts @@ -9,6 +9,7 @@ export class Menu { public data: any; // 用于记录当前菜单的数据 public removeCB: () => void; private wheelEvent: string; + private position: IPosition; constructor() { this.wheelEvent = "onwheel" in document.createElement("div") ? "wheel" : "mousewheel"; @@ -60,13 +61,12 @@ export class Menu { }); } - public showSubMenu(subMenuElement: HTMLElement | null) { - if (!subMenuElement) { - return; - } + public showSubMenu(subMenuElement: HTMLElement) { const itemsMenuElement = subMenuElement.lastElementChild as HTMLElement; if (itemsMenuElement) { itemsMenuElement.style.maxHeight = ""; + } else { + return; } const itemRect = subMenuElement.parentElement.getBoundingClientRect(); const subMenuRect = subMenuElement.getBoundingClientRect(); @@ -74,8 +74,8 @@ export class Menu { // 垂直方向位置调整 // 减 9px 是为了尽量对齐菜单选项(b3-menu__submenu 的默认 padding-top 加上子菜单首个 b3-menu__item 的默认 margin-top) // 减 1px 是为了避免在特定情况下渲染出不应存在的滚动条而做的兼容处理 - const top = Math.min(itemRect.top - 9, window.innerHeight - subMenuRect.height - 1); - subMenuElement.style.top = Math.max(Constants.SIZE_TOOLBAR_HEIGHT, top) + "px"; + subMenuElement.style.top = Math.max(Constants.SIZE_TOOLBAR_HEIGHT, + Math.min(itemRect.top - 9, window.innerHeight - subMenuRect.height - 1)) + "px"; // 水平方向位置调整 if (subMenuRect.right <= window.innerWidth) { @@ -93,14 +93,8 @@ export class Menu { } private updateMaxHeight(menuElement: HTMLElement, itemsMenuElement: HTMLElement) { - if (!menuElement || !itemsMenuElement) { - return; - } - const menuRect = menuElement.getBoundingClientRect(); - const itemsMenuRect = itemsMenuElement.getBoundingClientRect(); - // 加 1px 是为了避免在特定情况下渲染出不应存在的滚动条而做的兼容处理 - const availableHeight = (window.innerHeight - menuRect.top) - (menuRect.height - itemsMenuRect.height) + 1; - itemsMenuElement.style.maxHeight = Math.max(availableHeight, 0) + "px"; + // 加 1px 是为了避免在特定情况下渲染出不应存在的滚动条而做的兼容处理; 18 为父子块高差 + itemsMenuElement.style.maxHeight = Math.max(window.innerHeight - menuElement.getBoundingClientRect().top - 18 + 1, 30) + "px"; } private preventDefault(event: KeyboardEvent) { @@ -174,18 +168,18 @@ export class Menu { this.element.classList.remove("fn__none"); setPosition(this.element, options.x - (options.isLeft ? this.element.clientWidth : 0), options.y, options.h, options.w); this.updateMaxHeight(this.element, this.element.lastElementChild as HTMLElement); + this.position = options; } public resetPosition() { if (this.element.classList.contains("fn__none")) { return; } - setPosition(this.element, parseFloat(this.element.style.left), parseFloat(this.element.style.top), 0, 0); // 如果不存在 left 或 top,则得到 NaN + setPosition(this.element, this.position.x - (this.position.isLeft ? this.element.clientWidth : 0), this.position.y, this.position.h, this.position.w); this.updateMaxHeight(this.element, this.element.lastElementChild as HTMLElement); - const subMenuElements = this.element.querySelectorAll(".b3-menu__item--show .b3-menu__submenu") as NodeListOf; - subMenuElements.forEach((subMenuElement) => { + this.element.querySelectorAll(".b3-menu__item--show .b3-menu__submenu").forEach((item: HTMLElement) => { // 可能有多层子菜单,都要重新定位 - this.showSubMenu(subMenuElement); + this.showSubMenu(item); }); } diff --git a/app/src/util/setPosition.ts b/app/src/util/setPosition.ts index 8854439d8..d535a6a7e 100644 --- a/app/src/util/setPosition.ts +++ b/app/src/util/setPosition.ts @@ -1,39 +1,27 @@ import {Constants} from "../constants"; export const setPosition = (element: HTMLElement, left: number, top: number, targetHeight = 0, targetLeft = 0) => { - const isTopValid = !isNaN(top); // 存在 top 时调整垂直方向位置 - const isLeftValid = !isNaN(left); // 存在 left 时调整水平方向位置 - if (isTopValid) { - element.style.top = top + "px"; - } - if (isLeftValid) { - element.style.left = left + "px"; - } + element.style.top = top + "px"; + element.style.left = left + "px"; const rect = element.getBoundingClientRect(); - - if (isTopValid) { - if (rect.top < Constants.SIZE_TOOLBAR_HEIGHT) { - // 如果元素接触顶栏,向下移 - element.style.top = Constants.SIZE_TOOLBAR_HEIGHT + "px"; - } else if (rect.bottom > window.innerHeight) { + if (rect.top < Constants.SIZE_TOOLBAR_HEIGHT) { + // 如果元素接触顶栏,向下移 + element.style.top = Constants.SIZE_TOOLBAR_HEIGHT + "px"; + } else if (rect.bottom > window.innerHeight) { + const y = top - rect.height - targetHeight; + if (y > Constants.SIZE_TOOLBAR_HEIGHT && (y + rect.height) < window.innerHeight) { // 如果元素底部超出窗口(下方空间不够),向上移 - if (top - Constants.SIZE_TOOLBAR_HEIGHT >= rect.height) { - // 如果上方空间足够,向上移 - element.style.top = (top - rect.height - targetHeight) + "px"; - } else { - // 如果上下空间都不够,向上移,但尽量靠底部 - element.style.top = Math.max(Constants.SIZE_TOOLBAR_HEIGHT, window.innerHeight - rect.height) + "px"; - } + element.style.top = y + "px"; + } else { + // 如果上下空间都不够,向上移,但尽量靠底部 + element.style.top = Math.max(Constants.SIZE_TOOLBAR_HEIGHT, window.innerHeight - rect.height) + "px"; } } - - if (isLeftValid) { - if (rect.right > window.innerWidth) { - // 展现在左侧 - element.style.left = window.innerWidth - rect.width - targetLeft + "px"; - } else if (rect.left < 0) { - // 依旧展现在左侧,只是位置右移 - element.style.left = "0"; - } + if (rect.right > window.innerWidth) { + // 展现在左侧 + element.style.left = window.innerWidth - rect.width - targetLeft + "px"; + } else if (rect.left < 0) { + // 依旧展现在左侧,只是位置右移 + element.style.left = "0"; } };