如何为带搜索功能的下拉菜单创建可搜索分组?
解决下拉菜单分类搜索的匹配逻辑问题
我懂你的痛点——现在的搜索逻辑只盯着单个<li>的文本内容匹配,完全没考虑列表项所属的分类分组对吧?结果就是搜分类关键词时,只有标题<li>能显示,同分类下的其他对象因为文本里没带分类名就被藏起来;要是搜个没匹配到的内容,整个菜单直接空了,体验特别差。
咱们一步步调整,让搜索逻辑贴合你的需求:
第一步:给列表项绑定分类标识
先给每个属于分类的对象<li>加个data-category属性,把它和对应的分类标题关联起来,分类标题单独加个category-header类方便区分。示例HTML结构如下:
<div class="dropdown"> <input type="text" id="searchInput" placeholder="搜索分类或对象..."> <ul class="dropdown-menu"> <li class="category-header">电子产品</li> <li data-category="电子产品">手机</li> <li data-category="电子产品">笔记本电脑</li> <li class="category-header">家居用品</li> <li data-category="家居用品">沙发</li> <li data-category="家居用品">茶几</li> </ul> </div>
第二步:重写搜索逻辑
原来的搜索只是简单检查每个<li>的文本是否包含关键词,现在要改成:
- 搜分类名时,显示该分类的标题+所有下属对象
- 搜对象名时,显示该对象+它所属的分类标题
- 空搜索时显示全部内容
- 无匹配时显示提示,而非全隐藏
修改后的JS代码如下:
const input = document.getElementById('searchInput'); const menu = document.querySelector('.dropdown-menu'); const categoryHeaders = menu.querySelectorAll('.category-header'); const itemElements = menu.querySelectorAll('li:not(.category-header)'); input.addEventListener('input', function() { const searchTerm = this.value.trim().toLowerCase(); // 搜索框为空时,直接显示所有内容 if (!searchTerm) { categoryHeaders.forEach(header => header.style.display = 'block'); itemElements.forEach(item => item.style.display = 'block'); // 移除无结果提示 const noResult = menu.querySelector('.no-result'); if (noResult) noResult.remove(); return; } // 先隐藏所有内容,准备筛选 categoryHeaders.forEach(header => header.style.display = 'none'); itemElements.forEach(item => item.style.display = 'none'); // 用Set存需要显示的分类,避免重复 const categoriesToShow = new Set(); // 遍历所有对象,检查是否匹配关键词或所属分类匹配 itemElements.forEach(item => { const itemText = item.textContent.toLowerCase(); const itemCategory = item.dataset.category.toLowerCase(); if (itemText.includes(searchTerm) || itemCategory.includes(searchTerm)) { item.style.display = 'block'; categoriesToShow.add(item.dataset.category); } }); // 显示需要展示的分类标题 categoryHeaders.forEach(header => { const headerText = header.textContent; if (categoriesToShow.has(headerText) || headerText.toLowerCase().includes(searchTerm)) { header.style.display = 'block'; } }); // 处理无匹配的情况:显示提示 const visibleItems = menu.querySelectorAll('li[style="display: block;"]'); if (visibleItems.length === 0) { let noResult = menu.querySelector('.no-result'); if (!noResult) { noResult = document.createElement('li'); noResult.className = 'no-result'; noResult.textContent = '没有找到匹配的内容'; menu.appendChild(noResult); } noResult.style.display = 'block'; } else { // 有匹配就移除提示 const noResult = menu.querySelector('.no-result'); if (noResult) noResult.remove(); } });
第三步:(可选)优化样式区分分类和对象
给分类标题加个样式,让用户一眼就能区分分类和普通对象:
.category-header { font-weight: 600; color: #555; padding: 4px 8px; cursor: default; } .no-result { color: #999; font-style: italic; padding: 4px 8px; } .dropdown-menu li { padding: 4px 8px; cursor: pointer; }
这样调整后,搜“电子产品”时,分类标题和下面的手机、笔记本都会显示;搜“手机”时,手机和它的分类标题也会一起出来;要是搜个完全没匹配的词,菜单里会显示“没有找到匹配的内容”,再也不会全空啦!
内容的提问来源于stack exchange,提问作者anonymoose
相关产品推荐
相关产品推荐

