ContextmenuContent.vue 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <template>
  2. <ul class="contextmenu-content">
  3. <template v-for="(menu, index) in menus">
  4. <li
  5. v-if="!menu.hide"
  6. class="contextmenu-item"
  7. :key="menu.text || index"
  8. @click.stop="handleClickMenuItem(menu)"
  9. :class="{'divider': menu.divider, 'disable': menu.disable}"
  10. >
  11. <div class="contextmenu-item-content" :class="{'has-sub-menu': menu.children}" v-if="!menu.divider">
  12. <span class="text">{{menu.text}}</span>
  13. <span class="sub-text" v-if="menu.subText && !menu.children">{{menu.subText}}</span>
  14. <contextmenu-content
  15. class="sub-menu"
  16. :style="{
  17. [subMenuPosition]: '112.5%',
  18. }"
  19. :menus="menu.children"
  20. v-if="menu.children && menu.children.length"
  21. :handleClickMenuItem="handleClickMenuItem"
  22. />
  23. </div>
  24. </li>
  25. </template>
  26. </ul>
  27. </template>
  28. <script lang="ts">
  29. import { PropType } from 'vue'
  30. import { ContextmenuItem } from './types'
  31. export default {
  32. name: 'contextmenu-content',
  33. props: {
  34. menus: {
  35. type: Array as PropType<ContextmenuItem[]>,
  36. required: true,
  37. },
  38. subMenuPosition: {
  39. type: String,
  40. default: 'left',
  41. },
  42. handleClickMenuItem: {
  43. type: Function,
  44. required: true,
  45. },
  46. },
  47. }
  48. </script>
  49. <style lang="scss" scoped>
  50. $menuWidth: 160px;
  51. $menuHeight: 32px;
  52. $subMenuWidth: 120px;
  53. .contextmenu-content {
  54. width: $menuWidth;
  55. padding: 5px 0;
  56. background: #fff;
  57. border: 1px solid #ccc;
  58. box-shadow: 3px 3px 3px rgba(#000, 0.3);
  59. border-radius: 2px;
  60. list-style: none;
  61. margin: 0;
  62. }
  63. .contextmenu-item {
  64. padding: 0 20px;
  65. color: #555;
  66. font-size: 12px;
  67. transition: all 0.2s;
  68. white-space: nowrap;
  69. height: $menuHeight;
  70. line-height: $menuHeight;
  71. background-color: #fff;
  72. cursor: pointer;
  73. &:not(.disable):hover > .contextmenu-item-content > .sub-menu {
  74. display: block;
  75. }
  76. &:hover:not(.disable) {
  77. background-color: #e1e1e1;
  78. }
  79. &.divider {
  80. height: 1px;
  81. overflow: hidden;
  82. margin: 5px;
  83. background-color: #e5e5e5;
  84. line-height: 0;
  85. padding: 0;
  86. }
  87. &.disable {
  88. color: #b1b1b1;
  89. cursor: no-drop;
  90. }
  91. }
  92. .contextmenu-item-content {
  93. display: flex;
  94. align-items: center;
  95. justify-content: space-between;
  96. position: relative;
  97. &.has-sub-menu::before {
  98. content: '';
  99. display: inline-block;
  100. width: 0;
  101. height: 0;
  102. border-top: 4px solid transparent;
  103. border-left: 6px solid rgba($color: $themeColor, $alpha: .8);
  104. border-bottom: 4px solid transparent;
  105. position: absolute;
  106. right: 0;
  107. top: 50%;
  108. transform: translateY(-50%);
  109. }
  110. .sub-text {
  111. opacity: 0.6;
  112. }
  113. .sub-menu {
  114. position: absolute;
  115. top: -5px;
  116. display: none;
  117. width: $subMenuWidth;
  118. }
  119. }
  120. </style>