fix: 优化 SelectDropdown 下拉菜单定位逻辑以支持向上展开

This commit is contained in:
seahi committed 2026-09-28 20:42:36 +08:00
1 parent 8d1f3d0703
commit a3322f9750
1 file changed
+42 -5
+42 -5
View File
@@ -28,6 +28,12 @@
let triggerElement = $state<HTMLButtonElement>();
let menuElement = $state<HTMLDivElement>();
let menuTop = $state(0);
let menuBottom = $state(0);
let menuLeft = $state(0);
let menuWidth = $state(0);
let openUpwards = $state(false);
let selectedOption = $derived(options.find((option) => String(option.value) === String(value)));
let selectedLabel = $derived(selectedOption?.label ?? emptyLabel);
@@ -46,10 +52,37 @@
}
function openMenu(preferLast = false) {
if (triggerElement) {
const rect = triggerElement.getBoundingClientRect();
const spaceBelow = window.innerHeight - rect.bottom;
const spaceAbove = rect.top;
if (spaceBelow < 240 && spaceAbove > spaceBelow) {
openUpwards = true;
menuBottom = window.innerHeight - rect.top;
} else {
openUpwards = false;
menuTop = rect.bottom;
}
menuLeft = rect.left;
menuWidth = rect.width;
}
isOpen = true;
focusOption(preferLast);
}
function preventScroll(node: HTMLElement) {
const handler = (e: Event) => e.preventDefault();
node.addEventListener('wheel', handler, { passive: false });
node.addEventListener('touchmove', handler, { passive: false });
return {
destroy() {
node.removeEventListener('wheel', handler);
node.removeEventListener('touchmove', handler);
}
};
}
function closeMenu(restoreFocus = false) {
isOpen = false;
if (restoreFocus) triggerElement?.focus();
@@ -95,6 +128,8 @@
}
</script>
<svelte:window onresize={() => isOpen && closeMenu()} />
<div class="select-dropdown">
<input type="hidden" {name} {value} />
<button
@@ -120,6 +155,7 @@
aria-label={`关闭${label}菜单`}
tabindex="-1"
onclick={() => closeMenu()}
use:preventScroll
></button>
<div
class="select-dropdown-menu"
@@ -129,6 +165,11 @@
tabindex="-1"
bind:this={menuElement}
onkeydown={handleMenuKeydown}
style="top: {openUpwards ? 'auto' : `${menuTop}px`}; bottom: {openUpwards
? `${menuBottom}px`
: 'auto'}; left: {menuLeft}px; width: {menuWidth}px; margin-top: {openUpwards
? '0'
: '4px'}; margin-bottom: {openUpwards ? '4px' : '0'};"
>
<button
type="button"
@@ -219,15 +260,11 @@
}
.select-dropdown-menu {
position: absolute;
top: 100%;
left: 0;
right: 0;
position: fixed;
z-index: 51;
display: flex;
flex-direction: column;
max-height: 240px;
margin-top: 4px;
overflow-y: auto;
border: 1px solid var(--text-color);
background: var(--bg-color, #ffffff);