使用Svelte和shadcn-svelte实现搜索下拉组件遇焦点异常问题
解决Svelte+shadcn-svelte搜索组件焦点转移问题
你当前的问题核心是误用了DropdownMenu组件的触发逻辑——DropdownMenu.Trigger会在下拉框打开时自动抢占焦点,导致输入框失去焦点无法继续输入。而且这个场景下根本不需要DropdownMenu的点击触发机制,下拉框的显示/隐藏完全由输入内容控制,直接用普通容器实现更合适。
修改后的完整代码
<script lang="ts"> import { Input } from '$lib/components/ui/input'; import { cn } from '$lib/utils'; // 项目中常用的类名合并工具函数 let searchValue = ''; let filteredResults: string[] = []; let isDropdownOpen = false; const data = [ 'California', 'North Carolina', 'North Dakota', 'South Carolina', 'South Dakota', 'Michigan', 'Tennessee', 'Nevada', 'New Hampshire', 'New Jersey' ]; function handleInput() { filteredResults = data.filter(item => item.toLowerCase().includes(searchValue.toLowerCase()) ); isDropdownOpen = filteredResults.length > 0 && searchValue !== ''; } function handleItemSelection(item: string) { searchValue = item; // 选中后自动填充输入框 isDropdownOpen = false; // 关闭下拉框 console.log(`${item} selected`); } </script> <div class="relative w-full"> <Input bind:value={searchValue} on:input={handleInput} placeholder="Search..." class="w-full" /> {#if isDropdownOpen} <div class={cn( 'absolute top-full left-0 right-0 mt-1 border rounded-md bg-white shadow-lg z-10', 'max-h-60 overflow-y-auto' )} > {#each filteredResults as item} <div class="px-4 py-2 cursor-pointer hover:bg-gray-100 transition-colors" on:click={() => handleItemSelection(item)} > {item} </div> {/each} </div> {/if} </div>
关键修改说明
- 移除冗余组件:删掉了
DropdownMenu相关的所有代码,因为它的触发逻辑和焦点管理不适合输入驱动的下拉场景。 - 定位优化:用
relative容器包裹输入框和下拉结果,确保下拉框精准对齐输入框底部。 - 样式适配:自定义下拉容器的样式,对齐shadcn的设计风格,同时添加滚动条避免结果过多时溢出。
- 体验提升:选中下拉项时自动填充输入框并关闭下拉,符合常规搜索组件的交互逻辑。
如果一定要复用DropdownMenu的样式或键盘导航功能,也可以保留组件结构,但需要强制让输入框保持焦点——不过这种方式会增加不必要的复杂度,上面的方案是更直接的解决办法。
内容的提问来源于stack exchange,提问作者ZSmain
相关产品推荐
相关产品推荐

