index.vue 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. <template>
  2. <div class="hc-menu-simple-box" :class="ui">
  3. <template v-for="item in datas" :key="item.key">
  4. <div class="item-box" :class="item?.key === keysValue ? 'active' : ''" @click="MenuClick(item)" @contextmenu.prevent.stop="menuLabelContextMenu($event,item)">
  5. <div class="icon-box" v-if="item?.icon">
  6. <HcIcon :name="item?.icon" fill/>
  7. </div>
  8. <div class="label-box truncate">{{item?.label}}</div>
  9. <el-badge :value="item?.badge" v-if="item?.badge > 0"/>
  10. <!--操作菜单-->
  11. <div class="menu-icon" :class="item.showMenuIcon?'show':''" v-if="menusData.length > 0">
  12. <div class="menu-popover-icon" @click.prevent.stop="menuLabelContextMenu($event,item)">
  13. <HcIcon name="apps" ui="text-2xl"/>
  14. </div>
  15. </div>
  16. <!--操作菜单 END-->
  17. </div>
  18. </template>
  19. <!--右键菜单-->
  20. <HcContextMenu ref="contextMenuRef" :datas="menusData" @item-click="handleMenuSelect" v-if="menusData.length > 0" @closed="handleMenuClosed"/>
  21. </div>
  22. </template>
  23. <script setup>
  24. import { ref,watch } from "vue";
  25. import {getObjValue, isValueNull} from "vue-utils-plus"
  26. const props = defineProps({
  27. ui: {
  28. type: String,
  29. default: ''
  30. },
  31. datas: {
  32. type: Array,
  33. default: () => ([])
  34. },
  35. keys: {
  36. type: [String,Number],
  37. default: ''
  38. },
  39. menus: {
  40. type: Array,
  41. default: () => ([])
  42. },
  43. })
  44. //初始变量
  45. const keysValue = ref(props.keys)
  46. const menusData = ref(props.menus)
  47. const menuItemData = ref({})
  48. //监听
  49. watch(() => [
  50. props.keys,
  51. props.menus
  52. ], ([keys, menus]) => {
  53. menusData.value = menus
  54. keysValue.value = keys
  55. })
  56. //事件
  57. const emit = defineEmits(['change', 'menuTap'])
  58. const MenuClick = (item) => {
  59. if (item?.key !== keysValue.value) {
  60. emit('change', item)
  61. }
  62. }
  63. //鼠标右键事件
  64. const contextMenuRef = ref(null)
  65. const menuLabelContextMenu = (e,item) => {
  66. const rows = menusData.value || [];
  67. if (rows.length > 0) {
  68. e.preventDefault();
  69. menuItemData.value = item;
  70. item.showMenuIcon = true
  71. //展开菜单
  72. contextMenuRef.value?.showMenu(e)
  73. } else {
  74. menuItemData.value = false;
  75. item.showMenuIcon = false
  76. }
  77. }
  78. //鼠标右键菜单被点击
  79. const handleMenuSelect = ({key}) => {
  80. const item = getObjValue(menuItemData.value);
  81. emit('menuTap', {key, item})
  82. }
  83. //菜单关闭
  84. const handleMenuClosed = () => {
  85. const item = menuItemData.value;
  86. if (!isValueNull(item)) {
  87. menuItemData.value['showMenuIcon'] = false
  88. }
  89. }
  90. </script>
  91. <style lang="scss" scoped>
  92. .hc-menu-simple-box {
  93. position: relative;
  94. padding: 20px;
  95. .item-box {
  96. position: relative;
  97. display: flex;
  98. align-items: center;
  99. background: #f1f5f8;
  100. border-radius: 6px;
  101. padding: 8px 14px;
  102. margin-bottom: 10px;
  103. transition: 0.2s;
  104. .icon-box {
  105. position: relative;
  106. width: 22px;
  107. height: 22px;
  108. border-radius: 5px;
  109. background-color: var(--el-color-primary-light-8);
  110. color: var(--el-color-primary-light-5);
  111. font-size: 16px;
  112. display: flex;
  113. align-items: center;
  114. justify-content: center;
  115. margin-right: 14px;
  116. transition: 0.2s;
  117. }
  118. .label-box {
  119. position: relative;
  120. color: #838791;
  121. font-size: 14px;
  122. transition: 0.2s;
  123. flex: 1;
  124. }
  125. .menu-icon {
  126. position: relative;
  127. pointer-events: none;
  128. transition: opacity 0.2s;
  129. background: rgba(255, 255, 255, 0.25);
  130. border-radius: 2px;
  131. opacity: 0;
  132. .menu-popover-icon {
  133. display: flex;
  134. align-items: center;
  135. justify-content: center;
  136. color: #878787;
  137. }
  138. &.show {
  139. opacity: 1;
  140. pointer-events: all;
  141. cursor: context-menu;
  142. }
  143. }
  144. &:not(.active) {
  145. cursor: pointer;
  146. }
  147. &:hover {
  148. .icon-box {
  149. color: #ffffff;
  150. background-color: var(--el-color-primary);
  151. }
  152. .label-box {
  153. color: #1a1a1a;
  154. font-weight: 500;
  155. }
  156. .menu-icon {
  157. opacity: 1;
  158. pointer-events: all;
  159. cursor: context-menu;
  160. }
  161. }
  162. &.active {
  163. box-shadow: var(--hc-shadow);
  164. .icon-box {
  165. color: #ffffff;
  166. background-color: var(--el-color-primary);
  167. }
  168. .label-box {
  169. color: #1a1a1a;
  170. font-weight: 500;
  171. }
  172. }
  173. }
  174. }
  175. </style>
  176. <style lang="scss" scoped>
  177. .hc-menu-simple-box .item-box .el-badge {
  178. position: absolute;
  179. display: flex;
  180. right: 12px;
  181. }
  182. </style>