优化子菜单过渡效果,支持两套实现方案

This commit is contained in:
Hooray
2025-03-26 22:38:07 +08:00
parent 8b51977b32
commit 2f3f374fa0
+40 -37
View File
@@ -1,5 +1,6 @@
<script setup lang="ts">
import type { SubMenuProps } from './types'
import { cn } from '@/utils'
import { useTimeoutFn } from '@vueuse/core'
import Item from './item.vue'
import { rootMenuInjectionKey } from './types'
@@ -45,40 +46,42 @@ const transitionEvent = computed(() => {
el.style.overflow = ''
},
}
: {
enter(el: HTMLElement) {
requestAnimationFrame(() => {
el.dataset.height = el.offsetHeight.toString()
el.style.maxHeight = '0'
void el.offsetHeight
el.style.maxHeight = `${el.dataset.height}px`
: CSS.supports('height', 'calc-size(auto, size)')
? {}
: {
enter(el: HTMLElement) {
requestAnimationFrame(() => {
el.dataset.height = el.offsetHeight.toString()
el.style.maxHeight = '0'
void el.offsetHeight
el.style.maxHeight = `${el.dataset.height}px`
el.style.overflow = 'hidden'
})
},
afterEnter(el: HTMLElement) {
el.style.maxHeight = ''
el.style.overflow = ''
},
enterCancelled(el: HTMLElement) {
el.style.maxHeight = ''
el.style.overflow = ''
},
beforeLeave(el: HTMLElement) {
el.style.maxHeight = `${el.offsetHeight}px`
el.style.overflow = 'hidden'
})
},
afterEnter(el: HTMLElement) {
el.style.maxHeight = ''
el.style.overflow = ''
},
enterCancelled(el: HTMLElement) {
el.style.maxHeight = ''
el.style.overflow = ''
},
beforeLeave(el: HTMLElement) {
el.style.maxHeight = `${el.offsetHeight}px`
el.style.overflow = 'hidden'
},
leave(el: HTMLElement) {
el.style.maxHeight = '0'
},
afterLeave(el: HTMLElement) {
el.style.maxHeight = ''
el.style.overflow = ''
},
leaveCancelled(el: HTMLElement) {
el.style.maxHeight = ''
el.style.overflow = ''
},
}
},
leave(el: HTMLElement) {
el.style.maxHeight = '0'
},
afterLeave(el: HTMLElement) {
el.style.maxHeight = ''
el.style.overflow = ''
},
leaveCancelled(el: HTMLElement) {
el.style.maxHeight = ''
el.style.overflow = ''
},
}
})
const transitionClass = computed(() => {
@@ -93,11 +96,11 @@ const transitionClass = computed(() => {
}
: {
enterActiveClass: 'ease-in-out duration-300',
enterFromClass: 'opacity-0 translate-y-4 scale-95 blur-4',
enterFromClass: cn('opacity-0 translate-y-4 scale-95 blur-4', CSS.supports('height', 'calc-size(auto, size)') && 'h-0'),
enterToClass: 'opacity-100 translate-y-0 scale-100 blur-0',
leaveActiveClass: 'ease-in-out duration-300',
leaveFromClass: 'opacity-100 translate-y-0 scale-100 blur-0',
leaveToClass: 'opacity-0 translate-y-4 scale-95 blur-4',
leaveToClass: cn('opacity-0 translate-y-4 scale-95 blur-4', CSS.supports('height', 'calc-size(auto, size)') && 'h-0'),
}
})
@@ -140,7 +143,7 @@ function handleMouseenter() {
top = el.getBoundingClientRect().top + el.scrollTop
left = el.getBoundingClientRect().left + el.getBoundingClientRect().width
if (top + subMenuEl.offsetHeight > window.innerHeight) {
top = window.innerHeight - subMenuEl.offsetHeight
top = Math.max(0, window.innerHeight - subMenuEl.offsetHeight)
}
}
else {
@@ -188,7 +191,7 @@ function handleMouseleave() {
<Teleport v-if="hasChildren" to="body" :disabled="!rootMenu.isMenuPopup">
<Transition v-bind="transitionClass" v-on="transitionEvent">
<FaScrollArea
v-if="opened" ref="subMenuRef" :scrollbar="false" :mask="rootMenu.isMenuPopup" class="sub-menu static rounded-lg" :class="{
v-if="opened" ref="subMenuRef" :scrollbar="false" :mask="rootMenu.isMenuPopup" class="sub-menu static h-[calc-size(auto,size)] rounded-lg" :class="{
'bg-[var(--g-sub-sidebar-bg)]': rootMenu.isMenuPopup,
'border shadow-xl fixed! z-3000 w-[200px]': rootMenu.isMenuPopup,
'mx-1': rootMenu.isMenuPopup && (rootMenu.props.mode === 'vertical' || level !== 0),