Vanessa 2026-03-09 22:11:38 +08:00
parent 606986c0ca
commit 03352053ae
2 changed files with 30 additions and 48 deletions

View file

@ -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<HTMLElement>;
subMenuElements.forEach((subMenuElement) => {
this.element.querySelectorAll(".b3-menu__item--show .b3-menu__submenu").forEach((item: HTMLElement) => {
// 可能有多层子菜单,都要重新定位
this.showSubMenu(subMenuElement);
this.showSubMenu(item);
});
}

View file

@ -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";
}
};