|
@@ -1,19 +1,29 @@
|
|
<template>
|
|
<template>
|
|
<div class="hc-menu-simple-box" :class="ui">
|
|
<div class="hc-menu-simple-box" :class="ui">
|
|
- <template v-for="item in datas">
|
|
|
|
- <div class="item-box" :class="item?.key === keysValue ? 'active' : ''" @click="MenuClick(item)">
|
|
|
|
|
|
+ <template v-for="item in datas" :key="item.key">
|
|
|
|
+ <div class="item-box" :class="item?.key === keysValue ? 'active' : ''" @click="MenuClick(item)" @contextmenu.prevent.stop="menuLabelContextMenu($event,item)">
|
|
<div class="icon-box" v-if="item?.icon">
|
|
<div class="icon-box" v-if="item?.icon">
|
|
<HcIcon :name="item?.icon" fill/>
|
|
<HcIcon :name="item?.icon" fill/>
|
|
</div>
|
|
</div>
|
|
<div class="label-box truncate">{{item?.label}}</div>
|
|
<div class="label-box truncate">{{item?.label}}</div>
|
|
<el-badge :value="item?.badge" v-if="item?.badge > 0"/>
|
|
<el-badge :value="item?.badge" v-if="item?.badge > 0"/>
|
|
|
|
+ <!--操作菜单-->
|
|
|
|
+ <div class="menu-icon" :class="item.showMenuIcon?'show':''" v-if="menusData.length > 0">
|
|
|
|
+ <div class="menu-popover-icon" @click.prevent.stop="menuLabelContextMenu($event,item)">
|
|
|
|
+ <HcIcon name="apps" ui="text-2xl"/>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ <!--操作菜单 END-->
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
|
|
+ <!--右键菜单-->
|
|
|
|
+ <HcContextMenu ref="contextMenuRef" :datas="menusData" @item-click="handleMenuSelect" v-if="menusData.length > 0" @closed="handleMenuClosed"/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
import { ref,watch } from "vue";
|
|
import { ref,watch } from "vue";
|
|
|
|
+import {getObjValue, isValueNull} from "vue-utils-plus"
|
|
const props = defineProps({
|
|
const props = defineProps({
|
|
ui: {
|
|
ui: {
|
|
type: String,
|
|
type: String,
|
|
@@ -27,25 +37,63 @@ const props = defineProps({
|
|
type: [String,Number],
|
|
type: [String,Number],
|
|
default: ''
|
|
default: ''
|
|
},
|
|
},
|
|
|
|
+ menus: {
|
|
|
|
+ type: Array,
|
|
|
|
+ default: () => ([])
|
|
|
|
+ },
|
|
})
|
|
})
|
|
|
|
|
|
//初始变量
|
|
//初始变量
|
|
const keysValue = ref(props.keys)
|
|
const keysValue = ref(props.keys)
|
|
|
|
+const menusData = ref(props.menus)
|
|
|
|
+const menuItemData = ref({})
|
|
|
|
|
|
//监听
|
|
//监听
|
|
watch(() => [
|
|
watch(() => [
|
|
- props.keys
|
|
|
|
-], ([keys]) => {
|
|
|
|
|
|
+ props.keys,
|
|
|
|
+ props.menus
|
|
|
|
+], ([keys, menus]) => {
|
|
|
|
+ menusData.value = menus
|
|
keysValue.value = keys
|
|
keysValue.value = keys
|
|
})
|
|
})
|
|
|
|
|
|
//事件
|
|
//事件
|
|
-const emit = defineEmits(['change'])
|
|
|
|
|
|
+const emit = defineEmits(['change', 'menuTap'])
|
|
const MenuClick = (item) => {
|
|
const MenuClick = (item) => {
|
|
if (item?.key !== keysValue.value) {
|
|
if (item?.key !== keysValue.value) {
|
|
emit('change', item)
|
|
emit('change', item)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+//鼠标右键事件
|
|
|
|
+const contextMenuRef = ref(null)
|
|
|
|
+const menuLabelContextMenu = (e,item) => {
|
|
|
|
+ const rows = menusData.value || [];
|
|
|
|
+ if (rows.length > 0) {
|
|
|
|
+ e.preventDefault();
|
|
|
|
+ menuItemData.value = item;
|
|
|
|
+ item.showMenuIcon = true
|
|
|
|
+ //展开菜单
|
|
|
|
+ contextMenuRef.value?.showMenu(e)
|
|
|
|
+ } else {
|
|
|
|
+ menuItemData.value = false;
|
|
|
|
+ item.showMenuIcon = false
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//鼠标右键菜单被点击
|
|
|
|
+const handleMenuSelect = ({key}) => {
|
|
|
|
+ const item = getObjValue(menuItemData.value);
|
|
|
|
+ emit('menuTap', {key, item})
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//菜单关闭
|
|
|
|
+const handleMenuClosed = () => {
|
|
|
|
+ const item = menuItemData.value;
|
|
|
|
+ if (!isValueNull(item)) {
|
|
|
|
+ menuItemData.value['showMenuIcon'] = false
|
|
|
|
+ }
|
|
|
|
+}
|
|
</script>
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
<style lang="scss" scoped>
|
|
@@ -58,7 +106,7 @@ const MenuClick = (item) => {
|
|
align-items: center;
|
|
align-items: center;
|
|
background: #f1f5f8;
|
|
background: #f1f5f8;
|
|
border-radius: 6px;
|
|
border-radius: 6px;
|
|
- padding: 8px 12px;
|
|
|
|
|
|
+ padding: 8px 14px;
|
|
margin-bottom: 10px;
|
|
margin-bottom: 10px;
|
|
transition: 0.2s;
|
|
transition: 0.2s;
|
|
.icon-box {
|
|
.icon-box {
|
|
@@ -80,6 +128,26 @@ const MenuClick = (item) => {
|
|
color: #838791;
|
|
color: #838791;
|
|
font-size: 14px;
|
|
font-size: 14px;
|
|
transition: 0.2s;
|
|
transition: 0.2s;
|
|
|
|
+ flex: 1;
|
|
|
|
+ }
|
|
|
|
+ .menu-icon {
|
|
|
|
+ position: relative;
|
|
|
|
+ pointer-events: none;
|
|
|
|
+ transition: opacity 0.2s;
|
|
|
|
+ background: rgba(255, 255, 255, 0.25);
|
|
|
|
+ border-radius: 2px;
|
|
|
|
+ opacity: 0;
|
|
|
|
+ .menu-popover-icon {
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ justify-content: center;
|
|
|
|
+ color: #878787;
|
|
|
|
+ }
|
|
|
|
+ &.show {
|
|
|
|
+ opacity: 1;
|
|
|
|
+ pointer-events: all;
|
|
|
|
+ cursor: context-menu;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
&:not(.active) {
|
|
&:not(.active) {
|
|
cursor: pointer;
|
|
cursor: pointer;
|
|
@@ -93,6 +161,11 @@ const MenuClick = (item) => {
|
|
color: #1a1a1a;
|
|
color: #1a1a1a;
|
|
font-weight: 500;
|
|
font-weight: 500;
|
|
}
|
|
}
|
|
|
|
+ .menu-icon {
|
|
|
|
+ opacity: 1;
|
|
|
|
+ pointer-events: all;
|
|
|
|
+ cursor: context-menu;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
&.active {
|
|
&.active {
|
|
box-shadow: var(--hc-shadow);
|
|
box-shadow: var(--hc-shadow);
|