Files
OpenIsle/frontend_nuxt/components/DropdownMenu.vue
Tim 27ef792b11 Merge pull request #594 from immortal521/feat/user-menu-animation
feat: add transition effects for page and dropdown
2025-08-16 11:25:45 +08:00

105 lines
2.2 KiB
Vue

<template>
<div class="dropdown-wrapper" ref="wrapper">
<div class="dropdown-trigger" @click="toggle">
<slot name="trigger"></slot>
</div>
<Transition name="dropdown-menu">
<div v-if="visible" class="dropdown-menu-container">
<div
v-for="(item, idx) in items"
:key="idx"
class="dropdown-item"
:style="{ color: item.color || 'inherit' }"
@click="handle(item)"
>
{{ item.text }}
</div>
</div>
</Transition>
</div>
</template>
<script>
import { onBeforeUnmount, onMounted, ref } from 'vue'
export default {
name: 'DropdownMenu',
props: {
items: { type: Array, default: () => [] },
},
setup(props, { expose }) {
const visible = ref(false)
const wrapper = ref(null)
const toggle = () => {
visible.value = !visible.value
}
const close = () => {
visible.value = false
}
const handle = (item) => {
close()
if (item && typeof item.onClick === 'function') {
item.onClick()
}
}
const clickOutside = (e) => {
if (wrapper.value && !wrapper.value.contains(e.target)) {
close()
}
}
onMounted(() => {
document.addEventListener('click', clickOutside)
})
onBeforeUnmount(() => {
document.removeEventListener('click', clickOutside)
})
expose({ close })
return { visible, toggle, wrapper, handle }
},
}
</script>
<style scoped>
.dropdown-wrapper {
position: relative;
display: inline-block;
}
.dropdown-trigger {
cursor: pointer;
display: inline-flex;
align-items: center;
}
.dropdown-menu-enter-active,
.dropdown-menu-leave-active {
transition: all 0.4s;
}
.dropdown-menu-enter-from,
.dropdown-menu-leave-to {
opacity: 0;
transform: translateY(-16px);
}
.dropdown-menu-container {
position: absolute;
top: 100%;
right: 0;
background-color: var(--app-menu-background-color);
border: 1px solid var(--normal-border-color);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
border-radius: 8px;
min-width: 100px;
z-index: 2000;
}
.dropdown-item {
padding: 8px 16px;
white-space: nowrap;
cursor: pointer;
}
.dropdown-item:hover {
background-color: var(--menu-selected-background-color);
}
</style>