update
This commit is contained in:
81
src/ui/Widgets/Dropdown/Dropdown.vue
Normal file
81
src/ui/Widgets/Dropdown/Dropdown.vue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<div
|
||||
class="trigger"
|
||||
ref="trigger"
|
||||
@mouseenter="onMouseEnter"
|
||||
@touchstart="onMouseEnter"
|
||||
@mouseleave="onMouseLeave">
|
||||
<slot />
|
||||
</div>
|
||||
<Teleport to="#dropdowns">
|
||||
<div
|
||||
v-if="visible"
|
||||
ref="dropdown"
|
||||
class="dropdown"
|
||||
:class="{ visible }"
|
||||
@onmouseleave="visible = false">
|
||||
<slot name="content" />
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
const trigger = ref<HTMLDivElement>();
|
||||
const dropdown = ref<HTMLDivElement>();
|
||||
|
||||
const visible = ref(false);
|
||||
const top = ref('0px');
|
||||
const left = ref('0px');
|
||||
|
||||
function onMouseEnter(e: MouseEvent | TouchEvent) {
|
||||
visible.value = true;
|
||||
if (trigger.value) {
|
||||
const rect = trigger.value.getBoundingClientRect();
|
||||
top.value = rect.top + 'px';
|
||||
left.value = rect.width + rect.left + 'px';
|
||||
}
|
||||
window.addEventListener('touchstart', onWindowClick);
|
||||
window.addEventListener('click', onWindowClick);
|
||||
}
|
||||
|
||||
function outside(e: MouseEvent, el: HTMLElement) {
|
||||
const rect = el.getBoundingClientRect();
|
||||
return e.clientX < rect.x
|
||||
|| e.clientX > rect.x + rect.width
|
||||
|| e.clientY < rect.y
|
||||
|| e.clientY > rect.y + rect.height;
|
||||
}
|
||||
|
||||
function onWindowClick(e: MouseEvent | TouchEvent) {
|
||||
if (visible.value && e instanceof MouseEvent && dropdown.value && !outside(e, dropdown.value)) {
|
||||
visible.value = false;
|
||||
window.removeEventListener('touchstart', onWindowClick);
|
||||
window.removeEventListener('click', onWindowClick);
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseLeave(e: MouseEvent) {
|
||||
if (trigger.value && outside(e, trigger.value)) {
|
||||
visible.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dropdown {
|
||||
position: absolute;
|
||||
top: v-bind(top);
|
||||
left: v-bind(left);
|
||||
visibility: hidden;
|
||||
|
||||
&.visible {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user