1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- <template>
- <div
- class="mask"
- @contextmenu.prevent="removeContextmenu()"
- @mousedown.left="removeContextmenu()"
- ></div>
- <div
- class="contextmenu"
- :style="{
- left: style.left + 'px',
- top: style.top + 'px',
- }"
- @contextmenu.prevent
- >
- <MenuContent
- :menus="menus"
- :handleClickMenuItem="handleClickMenuItem"
- />
- </div>
- </template>
- <script lang="ts" setup>
- import { computed } from 'vue'
- import type { ContextmenuItem, Axis } from './types'
- import MenuContent from './MenuContent.vue'
- const props = defineProps<{
- axis: Axis
- el: HTMLElement
- menus: ContextmenuItem[]
- removeContextmenu: () => void
- }>()
- const style = computed(() => {
- const MENU_WIDTH = 180
- const MENU_HEIGHT = 30
- const DIVIDER_HEIGHT = 11
- const PADDING = 5
- const { x, y } = props.axis
- const menuCount = props.menus.filter(menu => !(menu.divider || menu.hide)).length
- const dividerCount = props.menus.filter(menu => menu.divider).length
- const menuWidth = MENU_WIDTH
- const menuHeight = menuCount * MENU_HEIGHT + dividerCount * DIVIDER_HEIGHT + PADDING * 2
- const screenWidth = document.body.clientWidth
- const screenHeight = document.body.clientHeight
- return {
- left: screenWidth <= x + menuWidth ? x - menuWidth : x,
- top: screenHeight <= y + menuHeight ? y - menuHeight : y,
- }
- })
- const handleClickMenuItem = (item: ContextmenuItem) => {
- if (item.disable) return
- if (item.children && !item.handler) return
- if (item.handler) item.handler(props.el)
- props.removeContextmenu()
- }
- </script>
- <style lang="scss">
- .mask {
- position: fixed;
- left: 0;
- top: 0;
- width: 100vw;
- height: 100vh;
- z-index: 9998;
- }
- .contextmenu {
- position: fixed;
- z-index: 9999;
- user-select: none;
- }
- </style>
|