如何基于shadcn实现输入触发式可搜索选择组件
实现仅在输入内容后显示下拉面板的搜索选择组件
要做出和谷歌搜索框、Mantine可搜索选择器一致的效果,核心就是只有当输入框有非空内容时,才触发下拉面板显示,以下是基于参考代码优化后的完整实现:
import { useState } from 'react'; import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem } from '@/components/ui/command'; import { Check } from '@/components/ui/check'; import { cn } from '@/lib/utils'; export default function SearchSelect() { const [value, setValue] = useState(''); const [open, setOpen] = useState(false); // 模拟业务数据源 const data = [ { name: 'React' }, { name: 'Vue' }, { name: 'Angular' }, { name: 'Svelte' }, ]; // 根据输入内容过滤匹配选项 const filteredItems = data.filter(item => item.name.toLowerCase().includes(value.trim().toLowerCase()) ); return ( <Command> <CommandInput value={value} placeholder="搜索框架..." onValueChange={(newValue) => { setValue(newValue); // 输入非空时打开面板,空输入直接关闭 setOpen(newValue.trim() !== ''); }} // 点击输入框时,若已有内容则自动打开面板 onFocus={() => { if (value.trim() !== '') { setOpen(true); } }} /> {/* 双重判断:面板处于打开状态 + 输入内容非空,才渲染下拉列表 */} {open && value.trim() !== '' && ( <CommandList> {filteredItems.length === 0 ? ( <CommandEmpty>未找到匹配的框架</CommandEmpty> ) : ( <CommandGroup> {filteredItems.map((item) => ( <CommandItem key={item.name} value={item.name} onSelect={(currentValue) => { setValue(currentValue); setOpen(false); // 选中选项后关闭面板 }} > <Check className={cn( 'mr-2 h-4 w-4', value === item.name ? 'opacity-100' : 'opacity-0' )} /> {item.name} </CommandItem> ))} </CommandGroup> )} </CommandList> )} </Command> ); }
关键逻辑说明
- 输入状态联动:在
onValueChange里直接根据输入内容是否为空控制open状态,避免无效的面板显示 - 聚焦触发优化:点击输入框时,若已有输入内容则自动打开面板,贴合用户操作直觉
- 选项过滤:实时根据输入内容过滤数据源,只展示匹配结果,和谷歌搜索框核心逻辑对齐
- 空状态处理:根据过滤后的结果动态显示空提示,比固定空提示更贴合实际场景
内容的提问来源于stack exchange,提问作者Rodiat Morin
相关产品推荐
相关产品推荐

