diff --git a/src/components/ContextMenu/index.ts b/src/components/ContextMenu/index.ts
index ad4ae593..dfc68459 100644
--- a/src/components/ContextMenu/index.ts
+++ b/src/components/ContextMenu/index.ts
@@ -1,3 +1,3 @@
export { createContextMenu, destroyContextMenu } from './src/createContextMenu'
-export * from './src/typing'
+export type { ContextMenuItem, CreateContextMenuOptions } from './src/typing'
diff --git a/src/components/ContextMenu/src/ContextMenu.vue b/src/components/ContextMenu/src/ContextMenu.vue
index 4169fbd8..d49cb738 100644
--- a/src/components/ContextMenu/src/ContextMenu.vue
+++ b/src/components/ContextMenu/src/ContextMenu.vue
@@ -1,54 +1,87 @@
-
+
diff --git a/src/components/ContextMenu/src/createContextMenu.ts b/src/components/ContextMenu/src/createContextMenu.ts
index 48db2bb8..f2502908 100644
--- a/src/components/ContextMenu/src/createContextMenu.ts
+++ b/src/components/ContextMenu/src/createContextMenu.ts
@@ -1,8 +1,9 @@
-import contextMenuVue from './ContextMenu.vue'
-import { isClient } from '@/utils/is'
-import { CreateContextOptions, ContextMenuProps } from './typing'
+import type { CreateContextMenuOptions, ContextMenuProps } from './typing'
+
import { createVNode, render } from 'vue'
+import contextMenuVue from './ContextMenu.vue'
+
const menuManager: {
domList: Element[]
resolve: Fn
@@ -11,33 +12,35 @@ const menuManager: {
resolve: () => {},
}
-export const createContextMenu = function (options: CreateContextOptions) {
- const { event } = options || {}
+/**
+ * 创建右键菜单
+ *
+ * Create a right-click menu
+ * @param options CreateContextMenuOptions
+ */
+export const createContextMenu = function (options: CreateContextMenuOptions) {
+ const { event = null, showIcon = true, styles = {}, items, width } = options || {}
event && event?.preventDefault()
- if (!isClient) {
- return
- }
+ if (typeof window === 'undefined') return
+
return new Promise((resolve) => {
const body = document.body
const container = document.createElement('div')
- const propsData: Partial = {}
- if (options.styles) {
- propsData.styles = options.styles
- }
-
- if (options.items) {
- propsData.items = options.items
- }
-
- if (options.event) {
- propsData.customEvent = event
- propsData.axis = { x: event.clientX, y: event.clientY }
+ const propsData: Partial = {
+ event,
+ styles,
+ showIcon,
+ items,
+ width,
+ axis: { x: event?.clientX || 0, y: event?.clientY || 0 },
}
+ /** create VNode */
const vm = createVNode(contextMenuVue, propsData)
+ /** render VNode */
render(vm, container)
const handleClick = function () {
@@ -51,7 +54,7 @@ export const createContextMenu = function (options: CreateContextOptions) {
try {
dom && body.removeChild(dom)
} catch (error) {
- // continue regardless of error
+ // continue
}
})
body.removeEventListener('click', handleClick)
@@ -69,6 +72,9 @@ export const createContextMenu = function (options: CreateContextOptions) {
})
}
+/**
+ * 销毁右键菜单
+ */
export const destroyContextMenu = function () {
if (menuManager) {
menuManager.resolve('')
diff --git a/src/components/ContextMenu/src/index.scss b/src/components/ContextMenu/src/index.scss
new file mode 100644
index 00000000..5c3a1914
--- /dev/null
+++ b/src/components/ContextMenu/src/index.scss
@@ -0,0 +1,69 @@
+$prefix-cls: '#{$tonyname}-context-menu';
+$default-height: 44px;
+
+@mixin item-style {
+ li {
+ display: inline-block;
+ width: 100%;
+ height: $default-height;
+ margin: 0 !important;
+ line-height: $default-height;
+
+ &.is-divider {
+ border-bottom: 1px solid var(--border-color, '#dedede');
+ }
+
+ &.el-sub-menu {
+ .el-sub-menu {
+ &__title {
+ height: $default-height;
+ line-height: $default-height;
+ }
+ }
+ }
+
+ &:not(.is-disabled):hover {
+ color: var(--text-primary-color);
+ background-color: #f1f2f3;
+ }
+ }
+}
+
+.#{$prefix-cls} {
+ @include item-style();
+
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: 200;
+ display: block;
+ width: 156px;
+ margin: 0;
+ list-style: none;
+ background-color: var(--background-primary-color);
+ border: 1px solid rgba(0, 0, 0, 0.08);
+ border-radius: 0.25rem;
+ box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.1), 0 1px 5px 0 rgba(0, 0, 0, 0.06);
+ background-clip: padding-box;
+ user-select: none;
+
+ &__text {
+ display: flex;
+ align-items: center;
+
+ span {
+ width: auto !important;
+ height: auto !important;
+ font-size: 14px;
+ visibility: visible !important;
+ }
+ }
+
+ &__popup {
+ @include item-style();
+
+ > ul {
+ padding: 0;
+ }
+ }
+}
diff --git a/src/components/ContextMenu/src/typing.ts b/src/components/ContextMenu/src/typing.ts
index 38ebd084..916af280 100644
--- a/src/components/ContextMenu/src/typing.ts
+++ b/src/components/ContextMenu/src/typing.ts
@@ -1,35 +1,141 @@
+import type { CSSProperties } from 'vue'
+
+/**
+ * 鼠标右击的轴数据
+ *
+ * Right-clicked axis data
+ */
export interface Axis {
+ /**
+ * x轴
+ *
+ * x-axis
+ */
x: number
+ /**
+ * x轴
+ *
+ * y-axis
+ */
y: number
}
-
+/**
+ * 右击菜单项的数据
+ *
+ * Right-click menu item data
+ */
export interface ContextMenuItem {
+ /**
+ * 菜单项名称
+ *
+ * Menu item name
+ */
label: string
+ /**
+ * 菜单项图标
+ *
+ * Menu item icon
+ */
icon?: string
+ /**
+ * 是否禁用
+ *
+ * Whether to disable
+ */
disabled?: boolean
+ /**
+ * 菜单项点击触发的函数
+ *
+ * The function triggered by the menu item click
+ */
handler?: Fn
+ /**
+ * 菜单项下方是否带分割线
+ *
+ * Whether there is a dividing line below the menu item
+ */
divider?: boolean
+ /**
+ * 菜单项的子项
+ *
+ * Children of menu items
+ */
children?: ContextMenuItem[]
}
-export interface CreateContextOptions {
+/**
+ * 右击菜单项的选项
+ *
+ * Right-click menu item options
+ */
+export interface CreateContextMenuOptions {
+ /**
+ * 右击的DOM的事件
+ *
+ * Right-clicked DOM events
+ */
event: MouseEvent
- icon?: string
- styles?: any
- items?: ContextMenuItem[]
+ /**
+ * 右击菜单项的数据
+ *
+ * Right-click menu item data
+ */
+ items: ContextMenuItem[]
+ /**
+ * 是否显示图标
+ *
+ * Whether to show the icon
+ */
+ showIcon?: boolean
+ /**
+ * 右击菜单的样式
+ *
+ * Right-click menu style
+ */
+ styles?: CSSProperties
+ /**
+ * 右击菜单的宽度
+ *
+ * Right-click menu width
+ */
+ width?: number
}
-export interface ContextMenuProps {
- event?: MouseEvent
- styles?: any
- items: ContextMenuItem[]
- customEvent?: MouseEvent
+/**
+ * 右击菜单Props
+ *
+ * Right click menu Props
+ */
+export interface ContextMenuProps extends CreateContextMenuOptions {
+ /**
+ * 右击菜单的轴偏移
+ *
+ * Axis Offset from right-click menu
+ */
axis?: Axis
- width?: number
- showIcon?: boolean
}
+/**
+ * 菜单项内容Props
+ *
+ * Menu item content Props
+ */
export interface ItemContentProps {
+ /**
+ * 是否显示图标
+ *
+ * Whether to show the icon
+ */
showIcon: boolean | undefined
+ /**
+ * 右击菜单项的数据
+ *
+ * Right-click menu item data
+ */
item: ContextMenuItem
+ /**
+ * 操作处理
+ *
+ * Action handling
+ */
handler: Fn
}
diff --git a/src/hooks/web/useContextMenu.ts b/src/hooks/web/useContextMenu.ts
index 7bf4cc05..b929fe5f 100644
--- a/src/hooks/web/useContextMenu.ts
+++ b/src/hooks/web/useContextMenu.ts
@@ -1,9 +1,16 @@
+export type { ContextMenuItem } from '@/components/ContextMenu'
+
import { onUnmounted, getCurrentInstance } from 'vue'
import { createContextMenu, destroyContextMenu } from '@/components/ContextMenu'
-import type { ContextMenuItem } from '@/components/ContextMenu'
-export type { ContextMenuItem }
-export function useContextMenu(authRemove = true) {
- if (getCurrentInstance() && authRemove) {
+
+/**
+ * 处理右键菜单
+ *
+ * Handling right-click menus
+ * @param autoRemove
+ */
+export function useContextMenu(autoRemove = true) {
+ if (getCurrentInstance() && autoRemove) {
onUnmounted(() => {
destroyContextMenu()
})
diff --git a/src/views/demo/tree/EditTree.vue b/src/views/demo/tree/EditTree.vue
index aa264595..954443dd 100644
--- a/src/views/demo/tree/EditTree.vue
+++ b/src/views/demo/tree/EditTree.vue
@@ -24,7 +24,7 @@ import { defineComponent } from 'vue'
import { ElCard, ElTree, ElRow, ElCol } from 'element-plus'
import { treeData } from './data'
import { useContextMenu } from '@/hooks/web/useContextMenu'
-import { CreateContextOptions } from '@/components/ContextMenu'
+import { CreateContextMenuOptions } from '@/components/ContextMenu'
import { Delete, Position } from '@element-plus/icons'
export default defineComponent({
@@ -54,7 +54,7 @@ export default defineComponent({
},
]
- const contextMenuOptions: CreateContextOptions = { event, items: MenuItems }
+ const contextMenuOptions: CreateContextMenuOptions = { event, items: MenuItems }
if (!contextMenuOptions.items?.length) return