原生 不支持搜索,必须用 select2 或 choices.js 等库实现;前者依赖 jQuery 适合传统项目,后者无依赖、轻量、现代友好,推荐多数场景使用。

原生 <select></select> 确实不支持搜索,别白费劲了
浏览器原生 <select></select> 元素在所有主流版本中都不提供内置搜索功能——不是你没开对配置,也不是 CSS 能 hack 出来。它本质是操作系统级控件(尤其在 macOS 和旧版 Windows 上),DOM 层面几乎不可干预。试图用 oninput、filter 或 contenteditable 伪实现,只会掉进 focus 失控、键盘导航断裂、屏幕阅读器不识别、移动端软键盘反复弹出等坑里。
用 select2 还是 choices.js?看这三点选
两个最常用轻量方案,差异不在“好不好”,而在“合不合你的场景”:
-
select2依赖 jQuery,如果项目已引入 jQuery 且需要远程搜索(ajax加载选项)、多语言、模板渲染,它依然稳定可靠;但若项目是纯现代 JS(ESM/Vite/React),引入 jQuery 反而增加包体积和维护负担 -
choices.js是原生 JS 实现,支持 ESM、无依赖、轻量(gzip 后 ~12KB),API 清晰,对disabled、required、data-*属性兼容好,适合大多数静态或简单动态选项场景 - 两者都支持键盘操作(
↑/↓切换、Enter选中、Escape关闭),但choices.js对form.reset()的响应更准确,select2需手动调用.val(null).trigger('change')
choices.js 最小可用集成示例(含关键配置)
不写框架、不加构建工具,直接 HTML + CDN 就能跑通:
<link href="https://cdn.jsdelivr.net/npm/choices.js@10.7.0/public/assets/styles/choices.min.css" rel="stylesheet" />
<select id="my-select" placeholder="请选择...">
<option value=""></option>
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
<option value="guangzhou">广州</option>
</select>
<script src="https://cdn.jsdelivr.net/npm/choices.js@10.7.0/public/assets/scripts/choices.min.js"></script>
<script>
const choices = new Choices('#my-select', {
searchEnabled: true,
shouldSort: false, // 默认会按文本排序,关掉更符合原始顺序
position: 'bottom', // 避免 dropdown 被父容器 overflow:hidden 截断
});
</script>
注意:必须保留空 <option value=""></option> 作为占位符,否则 placeholder 不显示;searchEnabled: true 是开关,缺省为 false;position 建议显式设为 'bottom' 或 'auto',避免在 modal 或 fixed 容器里错位。
搜索逻辑被忽略的细节:大小写、中文分词、防抖
默认搜索是「全字匹配 + 不区分大小写」,但中文用户常期望「输入“北”就出“北京”“北海”」,而原生 choices.js 搜索只做字符串 includes(),不支持拼音或分词。真要支持,得自己重写 searchChoices 方法:
- 大小写问题:默认已处理(
toLowerCase()),不用改 - 中文首字匹配:需替换默认搜索函数,用正则
/^[\u4e00-\u9fa5]/提取汉字首字再比对,或引入pinyin-pro做拼音转换 - 防抖:
choices.js内部没做防抖,高频输入可能卡顿,建议在初始化前用lodash.debounce包一层自定义搜索逻辑 - 空格行为:默认把空格当普通字符,若想支持“上海 浦东”匹配含这两个词的选项,得改搜索逻辑为分词后逐个
includes
这些扩展点都真实存在,但多数项目其实只需要基础搜索——先跑通,再按需加。

















