Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 30 additions & 14 deletions app/src/menus/Menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,20 @@ export class Menu {
}
const itemRect = subMenuElement.parentElement.getBoundingClientRect();
const subMenuRect = subMenuElement.getBoundingClientRect();

// 垂直方向位置调整
// 减 9px 是为了尽量对齐菜单选项(b3-menu__submenu 的默认 padding-top 加上子菜单首个 b3-menu__item 的默认 margin-top)
// 减 1px 是为了避免在特定情况下渲染出不应存在的滚动条而做的兼容处理
const itemsContainerEl = hasClosestByClassName(subMenuElement, "b3-menu__items");
let itemsPadLeft = 0;
let itemsPadRight = 0;
if (itemsContainerEl) {
const cs = getComputedStyle(itemsContainerEl);
itemsPadLeft = parseFloat(cs.paddingLeft) || 0;
itemsPadRight = parseFloat(cs.paddingRight) || 0;
}
const firstRow = itemsMenuElement.querySelector(".b3-menu__item, .b3-menu__separator");
const firstRowTopOffset = (firstRow ?? itemsMenuElement).getBoundingClientRect().top - subMenuRect.top; // 回退 itemsMenuElement 以兼容插件或 JS 片段插入的特殊子菜单

// 垂直方向与父级菜单项对齐
subMenuElement.style.top = Math.max(Constants.SIZE_TOOLBAR_HEIGHT,
Math.min(itemRect.top - 9, window.innerHeight - subMenuRect.height - 1)) + "px";
Math.min(itemRect.top - firstRowTopOffset, window.innerHeight - subMenuRect.height)) + "px";

// 水平方向位置调整
// 多级菜单继承上一级子菜单的方向
Expand All @@ -85,22 +93,21 @@ export class Menu {
isParentDirectionLeft = true;
}

// 8px 是 b3-menu__items 的默认 padding-right
const spaceRight = window.innerWidth - itemRect.right - 8;
const spaceLeft = itemRect.left - 8;
const spaceRight = window.innerWidth - itemRect.right - itemsPadRight;
const spaceLeft = itemRect.left - itemsPadLeft;
if (isParentDirectionLeft) {
if (spaceLeft >= subMenuRect.width) {
subMenuElement.style.left = (itemRect.left - 8 - subMenuRect.width) + "px";
subMenuElement.style.left = (itemRect.left - itemsPadLeft - subMenuRect.width) + "px";
} else if (spaceRight >= subMenuRect.width) {
subMenuElement.style.left = (itemRect.right + 8) + "px";
subMenuElement.style.left = (itemRect.right + itemsPadRight) + "px";
} else {
subMenuElement.style.left = Math.max(0, window.innerWidth - subMenuRect.width) + "px";
}
} else {
if (spaceRight >= subMenuRect.width) {
subMenuElement.style.left = (itemRect.right + 8) + "px";
subMenuElement.style.left = (itemRect.right + itemsPadRight) + "px";
} else if (spaceLeft >= subMenuRect.width) {
subMenuElement.style.left = (itemRect.left - 8 - subMenuRect.width) + "px";
subMenuElement.style.left = (itemRect.left - itemsPadLeft - subMenuRect.width) + "px";
} else {
subMenuElement.style.left = Math.max(0, window.innerWidth - subMenuRect.width) + "px";
}
Expand All @@ -110,8 +117,17 @@ export class Menu {
}

private updateMaxHeight(menuElement: HTMLElement, itemsMenuElement: HTMLElement) {
// 加 1px 是为了避免在特定情况下渲染出不应存在的滚动条而做的兼容处理; 18 为父子块高差
itemsMenuElement.style.maxHeight = Math.max(window.innerHeight - menuElement.getBoundingClientRect().top - 18 + 1, 30) + "px";
const menuRect = menuElement.getBoundingClientRect();
const itemsRect = itemsMenuElement.getBoundingClientRect();
const style = getComputedStyle(itemsMenuElement);
const cap = Math.max(30, window.innerHeight - itemsRect.top - Math.max(0, menuRect.bottom - itemsRect.bottom) - parseFloat(style.marginBottom) || 0);
// content-box 下 max-height 只限制 content,不包括 padding/border
let contentBoxExtra = 0;
if (style.boxSizing === "content-box") {
contentBoxExtra = (parseFloat(style.paddingTop) || 0) + (parseFloat(style.paddingBottom) || 0)
+ (parseFloat(style.borderTopWidth) || 0) + (parseFloat(style.borderBottomWidth) || 0);
}
itemsMenuElement.style.maxHeight = Math.max(0, cap - contentBoxExtra) + "px";
}

private preventDefault(event: KeyboardEvent) {
Expand Down
Loading