Files
mayfly-go/mayfly_go_web/src/components/contextmenu/index.vue

202 lines
4.8 KiB
Vue
Raw Normal View History

2023-04-05 22:41:53 +08:00
<template>
<transition @enter="onEnter" name="el-zoom-in-center">
<div
aria-hidden="true"
class="el-dropdown__popper el-popper is-light is-pure custom-contextmenu"
role="tooltip"
data-popper-placement="bottom"
:style="`top: ${state.dropdown.y + 5}px;left: ${state.dropdown.x}px;`"
:key="Math.random()"
v-show="state.isShow && !allHide"
>
2023-04-05 22:41:53 +08:00
<ul class="el-dropdown-menu">
<template v-for="(v, k) in state.dropdownList">
<li
:id="v.clickId"
v-auth="v.permission"
class="el-dropdown-menu__item"
aria-disabled="false"
tabindex="-1"
:key="k"
v-if="!v.affix && !v.isHide(state.item)"
@click="onCurrentContextmenuClick(v)"
>
2023-04-05 22:41:53 +08:00
<SvgIcon :name="v.icon" />
<span>{{ v.txt }}</span>
</li>
</template>
</ul>
<div v-if="state.arrowLeft > 0" class="el-popper__arrow" :style="{ left: `${state.arrowLeft}px` }"></div>
2023-04-05 22:41:53 +08:00
</div>
</transition>
</template>
<script setup lang="ts" name="layoutTagsViewContextmenu">
import { computed, reactive, onMounted, onUnmounted, watch } from 'vue';
import { ContextmenuItem } from './index';
import SvgIcon from '@/components/svgIcon/index.vue';
import { useWindowSize } from '@vueuse/core';
2023-04-05 22:41:53 +08:00
// 定义父组件传过来的值
const props = defineProps({
dropdown: {
type: Object,
default: () => {
return {
x: 0,
y: 0,
};
},
},
items: {
type: Array<ContextmenuItem>,
2023-11-03 17:09:20 +08:00
default: () => [],
2023-04-05 22:41:53 +08:00
},
});
// 定义子组件向父组件传值/事件
const emit = defineEmits(['currentContextmenuClick']);
const { width: vw, height: vh } = useWindowSize();
2023-04-05 22:41:53 +08:00
// 定义变量内容
const state = reactive({
isShow: false,
dropdownList: [] as ContextmenuItem[],
2023-04-05 22:41:53 +08:00
item: {} as any,
arrowLeft: 10,
dropdown: {
x: 0,
y: 0,
},
2023-04-05 22:41:53 +08:00
});
// 下拉菜单宽高
let contextmenuWidth = 117;
let contextmenuHeight = 117;
// 下拉菜单元素
let ele = null as any;
const onEnter = (el: any) => {
if (ele || el.offsetHeight == 0) {
return;
}
ele = el;
contextmenuHeight = el.offsetHeight;
contextmenuWidth = el.offsetWidth;
setDropdowns(props.dropdown);
};
const setDropdowns = (dropdown: any) => {
let { x, y } = dropdown;
state.arrowLeft = 10;
// `Dropdown 下拉菜单` 的宽度
if (x + contextmenuWidth > vw.value) {
state.arrowLeft = contextmenuWidth - (vw.value - x);
x = vw.value - contextmenuWidth - 5;
}
if (y + contextmenuHeight > vh.value) {
y = vh.value - contextmenuHeight - 5;
state.arrowLeft = 0;
}
state.dropdown.x = x;
state.dropdown.y = y;
};
const allHide = computed(() => {
for (let item of state.dropdownList) {
if (!item.isHide(state.item)) {
return false;
}
}
return true;
});
2023-04-05 22:41:53 +08:00
// 当前项菜单点击
const onCurrentContextmenuClick = (ci: ContextmenuItem) => {
// 存在点击事件,则触发该事件函数
if (ci.onClickFunc) {
ci.onClickFunc(state.item);
}
emit('currentContextmenuClick', { id: ci.clickId, item: state.item });
2023-04-05 22:41:53 +08:00
};
2023-04-05 22:41:53 +08:00
// 打开右键菜单:判断是否固定,固定则不显示关闭按钮
const openContextmenu = (item: any) => {
state.item = item;
closeContextmenu();
setTimeout(() => {
state.isShow = true;
}, 10);
};
2023-04-05 22:41:53 +08:00
// 关闭右键菜单
const closeContextmenu = () => {
state.isShow = false;
};
2023-04-05 22:41:53 +08:00
// 监听页面监听进行右键菜单的关闭
onMounted(() => {
document.body.addEventListener('click', closeContextmenu);
state.dropdownList = props.items;
2023-04-05 22:41:53 +08:00
});
2023-04-05 22:41:53 +08:00
// 页面卸载时,移除右键菜单监听事件
onUnmounted(() => {
document.body.removeEventListener('click', closeContextmenu);
});
2023-04-05 22:41:53 +08:00
watch(
() => props.dropdown,
() => {
// 元素置为空重新在onEnter赋值元素否则会造成堆栈溢出
ele = null;
2023-04-05 22:41:53 +08:00
},
{
deep: true,
}
);
2023-04-05 22:41:53 +08:00
watch(
() => props.items,
(x: any) => {
state.dropdownList = x;
2023-04-05 22:41:53 +08:00
},
{
deep: true,
}
);
// 暴露变量
defineExpose({
openContextmenu,
closeContextmenu,
});
</script>
<style scoped lang="scss">
.custom-contextmenu {
transform-origin: center top;
z-index: 2190;
position: fixed;
2023-12-20 17:29:16 +08:00
.el-dropdown-menu__item {
padding: 5px 12px;
2023-12-20 17:29:16 +08:00
}
2023-04-05 22:41:53 +08:00
.el-dropdown-menu__item {
font-size: 12px !important;
white-space: nowrap;
i {
font-size: 12px !important;
}
}
}
</style>
.