zs
2025-05-06 55bf797dcc730b37bc691ebab2b51ff9db8ed245
HIAWms/web/src/components/vue3-context-menu/ContextMenuInstance.ts
对比新文件
@@ -0,0 +1,133 @@
import { h, ref, render } from "vue";
import type { App, Slot } from "vue";
import type { ContextMenuInstance } from "./ContextMenuDefine";
import type { MenuOptions } from "./ContextMenuDefine";
import { checkOpenedContextMenu, closeContextMenu } from "./ContextMenuMutex";
import { genContainer, transformMenuPosition } from "./ContextMenuUtils";
import ContextMenuConstructor from './ContextMenu.vue'
import ContextSubMenuWrapperConstructor from './ContextSubMenuWrapper.vue'
import ContextSubMenuConstructor from './ContextSubMenu.vue'
import ContextMenuItemConstructor from './ContextMenuItem.vue'
import ContextMenuGroupConstructor from './ContextMenuGroup.vue'
import ContextMenuSeparatorConstructor from './ContextMenuSeparator.vue'
function initInstance(
  options: MenuOptions,
  container: HTMLElement,
  isNew: boolean,
  customSlots?: Record<string, Slot>,
) {
  const show = ref(true);
  const vnode = h(ContextSubMenuWrapperConstructor, {
    options: options,
    show: show,
    container: container,
    isFullScreenContainer: !isNew,
    onCloseAnimFinished: () => {
      render(null, container);
    },
    onClose: (item: undefined) => {
      options.onClose?.(item);
      show.value = false;
    },
  }, customSlots);
  render(vnode, container);
  return vnode.component;
}
//Show global contextmenu
function $contextmenu(options : MenuOptions, customSlots?: Record<string, Slot>) {
  const container = genContainer(options);
  const component = initInstance(options, container.container, container.isNew, customSlots);
  return (component as unknown as Record<string, unknown>).exposed as ContextMenuInstance;
}
export default {
  /**
   * For Vue install
   * @param app
   */
  install(app: App<Element>) : void {
    app.config.globalProperties.$contextmenu = $contextmenu;
    app.component('ContextMenu', ContextMenuConstructor);
    app.component('ContextMenuItem', ContextMenuItemConstructor);
    app.component('ContextMenuGroup', ContextMenuGroupConstructor);
    app.component('ContextMenuSperator', ContextMenuSeparatorConstructor);
    app.component('ContextMenuSeparator', ContextMenuSeparatorConstructor);
    app.component('ContextSubMenu', ContextSubMenuConstructor);
  },
  /**
   * Show a ContextMenu in page, same as `this.$contextmenu`
   *
   * For example:
   *
   * ```ts
   * onContextMenu(e : MouseEvent) {
   *   //prevent the browser's default menu
   *   e.preventDefault();
   *   //show your menu
   *   ContextMenu.showContextMenu({
   *     x: e.x,
   *     y: e.y,
   *     items: [
   *       {
   *         label: "A menu item",
   *         onClick: () => {
   *           alert("You click a menu item");
   *         }
   *       },
   *       {
   *         label: "A submenu",
   *         children: [
   *           { label: "Item1" },
   *           { label: "Item2" },
   *           { label: "Item3" },
   *         ]
   *       },
   *     ]
   *   });
   * }
   * ```
   *
   * You can pass customSlots to custom rendering this menu.
   *
   * For example, custom rendering #itemRender and #separatorRender:
   * ```ts
   *   ContextMenu.showContextMenu({
   *     ...
   *   } as MenuOptions, {
   *     //Use slot in function mode
   *     itemRender: ({ disabled, label, icon, showRightArrow, onClick, onMouseEnter }) => [  h('div', {
   *       class: 'my-menu-item'+(disabled?' disabled':''),
   *       onMouseenter: onMouseEnter,
   *       onClick: onClick,
   *     }, [
   *       icon ? h('img', { src: icon }) : h('div', { class: 'icon-place-holder' }),
   *       h('span', label),
   *       showRightArrow ? h('span', { class: 'right-arraw' }, '>>') : h('div'),
   *     ]) ],
   *     separatorRender: () => [ h('div', { class: 'my-menu-sperator' }) ]
   *   })
   * ```
   *
   * @param options The options of ContextMenu
   * @param customSlots You can provide some custom slots to customize the rendering style of the menu. These slots are the same as the slots of component ContextMenu.
   * @returns Menu instance
   */
  showContextMenu(options : MenuOptions, customSlots?: Record<string, Slot>) : ContextMenuInstance {
    return $contextmenu(options, customSlots);
  },
  /**
   * Get if there is a menu open now.
   */
  isAnyContextMenuOpen() {
    return checkOpenedContextMenu();
  },
  /**
   * Close the currently open menu
   */
  closeContextMenu,
  //Tools
  transformMenuPosition,
}