From 928c61ccddebc8d2c697b86ee9bee0c207330a8c Mon Sep 17 00:00:00 2001 From: schangxiang@126.com <schangxiang@126.com> Date: 周二, 06 5月 2025 07:18:22 +0800 Subject: [PATCH] 222 --- HIAWms/web/src/components/vue3-context-menu/ContextMenuUtils.ts | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 158 insertions(+), 0 deletions(-) diff --git a/HIAWms/web/src/components/vue3-context-menu/ContextMenuUtils.ts b/HIAWms/web/src/components/vue3-context-menu/ContextMenuUtils.ts new file mode 100644 index 0000000..14c27a9 --- /dev/null +++ b/HIAWms/web/src/components/vue3-context-menu/ContextMenuUtils.ts @@ -0,0 +1,158 @@ +import { defineComponent, toRefs } from "vue"; +import type { VNode } from "vue"; +import type { MenuOptions } from "./ContextMenuDefine"; +import { MenuConstOptions } from "./ContextMenuDefine"; + +/** + * Get absolute y position of HTMLElement + * @param e Element + * @param stopNode Specify the node for recursive termination, default to body + * @returns + */ +export function getTop(e: HTMLElement, stopNode?: HTMLElement): number { + let offset = e.offsetTop; + if (e.offsetParent != null && e.offsetParent != stopNode) { + offset -= e.offsetParent.scrollTop; + offset += getTop(e.offsetParent as HTMLElement, stopNode); + } + return offset; +} +/** + * Get absolute x position of HTMLElement + * @param e Element + * @param stopNode Specify the node for recursive termination, default to body + * @returns + */ +export function getLeft(e: HTMLElement, stopNode?: HTMLElement): number { + let offset = e.offsetLeft; + if (e.offsetParent != null && e.offsetParent != stopNode) { + offset -= e.offsetParent.scrollLeft; + offset += getLeft(e.offsetParent as HTMLElement, stopNode); + } + return offset; +} + +/** + * If your `body` element is in a scaled state (e.g. `transform: scale(0.5)`), + * this may lead to the wrong position of the menu display. + * You can use this function to transform the menu display position: + * + * ```ts + * + import ContextMenu from '@imengyu/vue3-context-menu' + + function onContextMenu(e: MouseEvent) { + const scaledPosition = ContextMenu.transformMenuPosition(e.target as HTMLElement, e.offsetX, e.offsetY); + //Full code of menuData is in `/examples/views/InScaledBody.vue` + menuData.x = scaledPosition.x; + menuData.y = scaledPosition.y; + //show menu + ContextMenu.showContextMenu(menuData); + } + * ``` + * @param e Current click element + * @param offsetX MouseEvent.offsetX + * @param offsetY MouseEvent.offsetY + */ +export function transformMenuPosition( + e: HTMLElement, + offsetX: number, + offsetY: number, + container?: HTMLElement +): { + x: number; + y: number; +} { + return { + x: getLeft(e, container) + offsetX, + y: getTop(e, container) + offsetY, + }; +} + +const DEFAULT_CONTAINER_ID = "mx-menu-default-container"; +const GEN_CONTAINER_ID = "mx-menu-container-"; +let containerId = 0; + +export function removeContainer(container: HTMLElement): void { + container.parentNode?.removeChild(container); +} +export function genContainer(options: MenuOptions): { + eleId: string; + container: HTMLElement; + isNew: boolean; +} { + const { getContainer, zIndex } = options; + + if (getContainer) { + const container = + typeof getContainer === "function" ? getContainer() : getContainer; + if (container) { + let eleId = container.getAttribute("id"); + if (!eleId) { + eleId = GEN_CONTAINER_ID + containerId++; + container.setAttribute("id", eleId); + } + return { + eleId, + container, + isNew: false, + }; + } + } + + let container = document.getElementById(DEFAULT_CONTAINER_ID); + if (!container) { + container = document.createElement("div"); + container.setAttribute("id", DEFAULT_CONTAINER_ID); + container.setAttribute( + "class", + "mx-menu-ghost-host information_full_screen" + ); + document.body.appendChild(container); + } + container.style.zIndex = + zIndex?.toString() || MenuConstOptions.defaultZindex.toString(); + return { + eleId: DEFAULT_CONTAINER_ID, + container, + isNew: true, + }; +} + +/** + * Number to px string + * @param value + * @returns + */ +export function solveNumberOrStringSize(value: string | number): string { + return typeof value === "number" ? `${value}px` : value; +} + +/** + * Render a VNode + */ +export const VNodeRender = defineComponent({ + props: { + /** + * Can be VNode or (data: unknown) => VNode + */ + vnode: { + type: null, + }, + /** + * If vnode is a callback, this data will be passed to the callback first parameter. + * @default null + */ + data: { + type: null, + default: null, + }, + }, + setup(props) { + const { vnode, data } = toRefs(props); + return () => + typeof vnode.value === "function" + ? (vnode.value as unknown as (data: unknown) => VNode)(data.value) + : (vnode.value as unknown as VNode); + }, +}); -- Gitblit v1.9.3