fix: 优化 SelectDropdown 下拉菜单定位逻辑以支持向上展开
This commit is contained in:
1 parent
8d1f3d0703
commit
a3322f9750
1 file changed
+42
-5
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user