index.vue 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. <template>
  2. <div
  3. class="mask"
  4. @contextmenu.prevent="removeContextmenu()"
  5. @mousedown.left="removeContextmenu()"
  6. ></div>
  7. <div
  8. class="contextmenu"
  9. :style="{
  10. left: style.left + 'px',
  11. top: style.top + 'px',
  12. }"
  13. @contextmenu.prevent
  14. >
  15. <MenuContent
  16. :menus="menus"
  17. :handleClickMenuItem="handleClickMenuItem"
  18. />
  19. </div>
  20. </template>
  21. <script lang="ts" setup>
  22. import { computed } from 'vue'
  23. import type { ContextmenuItem, Axis } from './types'
  24. import MenuContent from './MenuContent.vue'
  25. const props = defineProps<{
  26. axis: Axis
  27. el: HTMLElement
  28. menus: ContextmenuItem[]
  29. removeContextmenu: () => void
  30. }>()
  31. const style = computed(() => {
  32. const MENU_WIDTH = 180
  33. const MENU_HEIGHT = 30
  34. const DIVIDER_HEIGHT = 11
  35. const PADDING = 5
  36. const { x, y } = props.axis
  37. const menuCount = props.menus.filter(menu => !(menu.divider || menu.hide)).length
  38. const dividerCount = props.menus.filter(menu => menu.divider).length
  39. const menuWidth = MENU_WIDTH
  40. const menuHeight = menuCount * MENU_HEIGHT + dividerCount * DIVIDER_HEIGHT + PADDING * 2
  41. const screenWidth = document.body.clientWidth
  42. const screenHeight = document.body.clientHeight
  43. return {
  44. left: screenWidth <= x + menuWidth ? x - menuWidth : x,
  45. top: screenHeight <= y + menuHeight ? y - menuHeight : y,
  46. }
  47. })
  48. const handleClickMenuItem = (item: ContextmenuItem) => {
  49. if (item.disable) return
  50. if (item.children && !item.handler) return
  51. if (item.handler) item.handler(props.el)
  52. props.removeContextmenu()
  53. }
  54. </script>
  55. <style lang="scss">
  56. .mask {
  57. position: fixed;
  58. left: 0;
  59. top: 0;
  60. width: 100vw;
  61. height: 100vh;
  62. z-index: 9998;
  63. }
  64. .contextmenu {
  65. position: fixed;
  66. z-index: 9999;
  67. user-select: none;
  68. }
  69. </style>