如何实现带分组悬停展示子项的多选嵌套列表?
实现optgroup悬停展示子选项的方案
原生<select>标签的<optgroup>元素受浏览器默认样式与行为限制,很难直接实现悬停时右侧展示子选项的交互,因此我们可以通过自定义UI结构来模拟该功能,具体实现方案如下:
实现步骤
- 用自定义HTML结构模拟原生select的分组与选项,原生控件可隐藏以保留表单提交功能
- 为每个分组项绑定
mouseover事件,触发时生成对应子选项的悬浮列表并定位到分组右侧 - 为分组项及悬浮列表绑定
mouseout事件,控制列表的隐藏逻辑 - 通过CSS调整悬浮列表的样式与定位,保证交互体验
完整代码示例
HTML 结构
<!-- 隐藏原生select,用于表单提交时保留选中值 --> <select id='optSelect' multiple style="display: none;"> <optgroup label='Option1'> <option value='Option1'>Option1</option> <option value='Option12'>Option12</option> <option value='Option13'>Option13</option> </optgroup> <optgroup label='Option2'> <option value='Option21'>Option21</option> <option value='Option22'>Option22</option> <option value='Option23'>Option23</option> </optgroup> <optgroup label='Option3'> <option value='Option31'>Option31</option> <option value='Option32'>Option32</option> <option value='Option33'>Option33</option> </optgroup> </select> <!-- 自定义模拟UI --> <div class="custom-select-container"> <div class="custom-optgroup" data-group="Option1"> <span class="group-label">Option1</span> </div> <div class="custom-optgroup" data-group="Option2"> <span class="group-label">Option2</span> </div> <div class="custom-optgroup" data-group="Option3"> <span class="group-label">Option3</span> </div> </div> <!-- 悬浮列表容器 --> <div id="hover-options" class="hover-options"></div>
CSS 样式
.custom-select-container { width: 200px; border: 1px solid #ccc; border-radius: 4px; } .custom-optgroup { padding: 8px 12px; background-color: #f8f8f8; border-bottom: 1px solid #eee; cursor: pointer; position: relative; } .custom-optgroup:last-child { border-bottom: none; } .custom-optgroup:hover { background-color: #e8e8e8; } .hover-options { position: absolute; border: 1px solid #ccc; border-radius: 4px; background-color: #fff; box-shadow: 0 2px 8px rgba(0,0,0,0.1); padding: 0; margin: 0; list-style: none; display: none; z-index: 100; } .hover-options li { padding: 8px 12px; min-width: 150px; font-size: 15px; } .hover-options li:hover { background-color: #e8e8e8; }
JavaScript 逻辑
const customOptgroups = document.querySelectorAll('.custom-optgroup'); const hoverOptions = document.getElementById('hover-options'); const nativeSelect = document.getElementById('optSelect'); // 绑定分组悬停事件 customOptgroups.forEach(group => { group.addEventListener('mouseover', function() { const groupLabel = this.dataset.group; // 匹配原生select中对应的分组 const nativeOptgroup = nativeSelect.querySelector(`optgroup[label="${groupLabel}"]`); const options = nativeOptgroup.querySelectorAll('option'); // 生成悬浮列表内容 hoverOptions.innerHTML = ''; options.forEach(opt => { const li = document.createElement('li'); li.textContent = opt.textContent; li.dataset.value = opt.value; // 点击悬浮选项时同步原生select的选中状态 li.addEventListener('click', function() { opt.selected = !opt.selected; }); hoverOptions.appendChild(li); }); // 定位悬浮列表并显示 const rect = this.getBoundingClientRect(); hoverOptions.style.top = `${rect.top + window.scrollY}px`; hoverOptions.style.left = `${rect.right + 10}px`; hoverOptions.style.display = 'block'; }); group.addEventListener('mouseout', function() { hoverOptions.style.display = 'none'; }); // 鼠标移入悬浮列表时保持显示 hoverOptions.addEventListener('mouseover', function() { this.style.display = 'block'; }); hoverOptions.addEventListener('mouseout', function() { this.style.display = 'none'; }); });
方案说明
- 原生
<select>仅用于表单提交时传递选中值,不影响前端交互逻辑 - 自定义UI完全可控,可根据需求调整样式与交互细节
- 悬浮选项的点击操作同步原生select状态,保证数据一致性
内容的提问来源于stack exchange,提问作者user312149
相关产品推荐
相关产品推荐

