<template>
<div class="drp_component" :class="classname">
<p @click="openDrp" class="ws-n" ref="drpDef" title="">
<slot></slot>
</p>
</div>
<transition :name="openType">
<div
:style="{ top: top + 'px', left: left + 'px' }"
class="drp_item_wrap"
ref="drpItemWrap"
v-if="show"
@click="show = false"
title=""
>
<slot name="dropdown"></slot>
<span
class="arrow"
:class="{
arror_top: arrowPosition === 'top',
arror_bottom: arrowPosition === 'bottom',
}"
:style="{ left: arrowLeft + 'px' }"
></span>
</div>
</transition>
</template>
<script>
export default {
name: "HelloWorld",
};
</script>
<script setup>
import { nextTick, ref, watch } from "vue";
import $ from "jquery";
const openType = ref("");
const classname = ref(Math.random().toString(36).substr(2));
const show = ref(false);
const top = ref(9999999);
const left = ref(9999999);
const arrowLeft = ref(0);
const arrowPosition = ref("");
const openDrp = () => {
show.value = !show.value;
if (!show.value) return;
nextTick(() => {
const body = document.querySelector("body");
if (body.append) {
body.append(drpItemWrap.value);
} else {
body.appendChild(drpItemWrap.value);
}
let dcWidth = document.body.clientWidth;
let dcHeight = document.body.clientHeight;
let pLeft =
$(`.${classname.value}`).offset().left - document.documentElement.scrollLeft;
let pTop = $(`.${classname.value}`).offset().top - document.documentElement.scrollTop;
let pWidth = $(`.${classname.value}`).outerWidth();
let pHeight = $(`.${classname.value}`).outerHeight();
let itemWidth = $(".drp_item_wrap").outerWidth();
let itemHeight = $(".drp_item_wrap").outerHeight();
if (pTop + pHeight + itemHeight - dcHeight > 0) {
top.value = pTop - itemHeight - 10;
arrowPosition.value = "bottom";
openType.value = "el-zoom-in-bottom";
} else {
top.value = pTop + pHeight + 10;
arrowPosition.value = "top";
openType.value = "el-zoom-in-top";
}
if (pLeft + pWidth / 2 - itemWidth / 2 < 0) {
left.value = 10;
arrowLeft.value = pLeft - 10 + pWidth / 2 - 7;
} else if (pLeft + pWidth / 2 + itemWidth / 2 > dcWidth) {
left.value = dcWidth - itemWidth - 10;
arrowLeft.value = pLeft - left.value + pWidth / 2 - 7;
} else {
left.value = pLeft + pWidth / 2 - itemWidth / 2;
arrowLeft.value = itemWidth / 2 - 7;
}
show.value = !show.value;
setTimeout(() => {
show.value = !show.value;
});
});
};
const colse = () => {
if (show.value) show.value = false;
};
const drpDef = ref(null);
const drpItemWrap = ref(null);
const cm = (e) => {
if (
drpItemWrap.value &&
!drpItemWrap.value.contains(e.target) &&
drpDef.value &&
!drpDef.value.contains(e.target)
) {
colse();
}
};
watch(show, (v) => {
if (v) {
window.addEventListener("scroll", colse);
window.addEventListener("wheel", colse);
window.addEventListener("mousedown", cm);
} else {
window.removeEventListener("scroll", colse);
window.removeEventListener("wheel", colse);
window.removeEventListener("mousedown", cm);
}
});
</script>
<style lang="less">
.drp_component {
line-height: 1;
}
.drp_item_wrap {
line-height: 1;
background-color: #fff;
padding: 5px 0 5px;
border: 1px solid var(--el-border-color-light);
box-shadow: var(--el-box-shadow-light);
position: fixed;
z-index: 9999999;
border-radius: 4px;
> div {
padding: 10px 16px;
cursor: pointer;
user-select: none;
font-size: 14px;
text-align: left;
white-space: nowrap;
}
> div:hover {
background-color: var(--el-color-primary-light-9);
color: var(--el-color-primary);
}
> button {
border: none;
outline: none;
padding: 6px 16px;
cursor: pointer;
user-select: none;
font-size: 14px;
text-align: left;
white-space: nowrap;
background-color: #fff;
display: block;
width: 100%;
}
> button:hover {
background-color: var(--el-color-primary-light-9);
color: var(--el-color-primary);
}
> button[disabled] {
background-color: #fff;
cursor: not-allowed;
color: #8F9BB3;
}
.arrow {
position: absolute;
width: 10px;
height: 10px;
border: 1px solid var(--el-border-color-light);
z-index: -1;
transform: rotate(45deg);
background-color: #fff;
}
.arror_top {
top: -5px;
border-bottom-color: transparent;
border-right-color: transparent;
}
.arror_bottom {
bottom: -5px;
border-top-color: transparent;
border-left-color: transparent;
}
}
</style>