在Ruby on Rails的HAML中创建复选框下拉菜单的方法
解决方案
要把杂乱的复选框改成带复选框的下拉菜单,我们可以基于Bootstrap自定义下拉组件,配合Simple Form的collection_check_boxes实现整洁排版,同时添加交互优化(比如显示选中项、全选/取消全选)。
修改后的完整代码(Haml)
.card-header.d-flex.align-items-center %span Listing Students = link_to 'New Student', new_student_path, class: 'btn btn-outline-secondary ms-auto' %button.btn.btn-outline-secondary.dropdown-toggle.mr-2#filter-button{type: "button", "data-bs-toggle": "dropdown", "aria-expanded": "false"} Filter %ul.dropdown-menu{aria-labelledby: "filter-button", style: "min-width: 300px;"} %li.p-3 = simple_form_for :filter, url: filter_students_path, method: :post do |f| = f.input :givenname, wrapper: :vertical_form, input_html: {class: 'form-control'} # 课程筛选:带复选框的下拉 %div.mb-3 %button.btn.btn-outline-secondary.w-100.text-start.dropdown-toggle{type: "button", "data-bs-toggle": "dropdown", "aria-expanded": "false"} %span#selected-courses 选择课程 %ul.dropdown-menu.w-100 %li.p-2 = f.collection_check_boxes(:course_ids, Course.all, :id, :course_code, include_hidden: false) do |b| %div.form-check.mb-1 = b.check_box(class: 'form-check-input') = b.label(class: 'form-check-label') %div.d-flex.justify-content-between.mt-2 %button.btn.btn-sm.btn-outline-secondary.select-all{type: 'button'} 全选 %button.btn.btn-sm.btn-outline-secondary.deselect-all{type: 'button'} 取消全选 # 地点筛选:同理修改 %div.mb-3 %button.btn.btn-outline-secondary.w-100.text-start.dropdown-toggle{type: "button", "data-bs-toggle": "dropdown", "aria-expanded": "false"} %span#selected-locations 选择地点 %ul.dropdown-menu.w-100 %li.p-2 = f.collection_check_boxes(:location_ids, Location.all, :id, :location_name, include_hidden: false) do |b| %div.form-check.mb-1 = b.check_box(class: 'form-check-input') = b.label(class: 'form-check-label') %div.d-flex.justify-content-between.mt-2 %button.btn.btn-sm.btn-outline-secondary.select-all-loc{type: 'button'} 全选 %button.btn.btn-sm.btn-outline-secondary.deselect-all-loc{type: 'button'} 取消全选 # 行业筛选:同理修改 %div.mb-3 %button.btn.btn-outline-secondary.w-100.text-start.dropdown-toggle{type: "button", "data-bs-toggle": "dropdown", "aria-expanded": "false"} %span#selected-sectors 选择行业 %ul.dropdown-menu.w-100 %li.p-2 = f.collection_check_boxes(:sector_ids, Sector.all, :id, :sector_name, include_hidden: false) do |b| %div.form-check.mb-1 = b.check_box(class: 'form-check-input') = b.label(class: 'form-check-label') %div.d-flex.justify-content-between.mt-2 %button.btn.btn-sm.btn-outline-secondary.select-all-sec{type: 'button'} 全选 %button.btn.btn-sm.btn-outline-secondary.deselect-all-sec{type: 'button'} 取消全选 %div.d-flex.gap-2 = f.submit 'Search', class: 'btn btn-primary' = link_to 'Reset', students_path, class: 'btn btn-outline-secondary'
配套JavaScript(添加到页面或JS文件)
document.addEventListener('DOMContentLoaded', function() { // 通用更新选中项文本的函数 function updateSelectedText(checkboxSelector, spanId, defaultText) { const checkboxes = document.querySelectorAll(checkboxSelector); const span = document.getElementById(spanId); const selected = Array.from(checkboxes) .filter(cb => cb.checked) .map(cb => cb.nextElementSibling.textContent); span.textContent = selected.length > 0 ? selected.join(', ') : defaultText; } // 课程筛选交互 const courseCheckboxes = 'input[name="filter[course_ids][]"]'; updateSelectedText(courseCheckboxes, 'selected-courses', '选择课程'); document.querySelectorAll(courseCheckboxes).forEach(cb => { cb.addEventListener('change', () => updateSelectedText(courseCheckboxes, 'selected-courses', '选择课程')); }); document.querySelector('.select-all').addEventListener('click', () => { document.querySelectorAll(courseCheckboxes).forEach(cb => cb.checked = true); updateSelectedText(courseCheckboxes, 'selected-courses', '选择课程'); }); document.querySelector('.deselect-all').addEventListener('click', () => { document.querySelectorAll(courseCheckboxes).forEach(cb => cb.checked = false); updateSelectedText(courseCheckboxes, 'selected-courses', '选择课程'); }); // 地点筛选交互 const locationCheckboxes = 'input[name="filter[location_ids][]"]'; updateSelectedText(locationCheckboxes, 'selected-locations', '选择地点'); document.querySelectorAll(locationCheckboxes).forEach(cb => { cb.addEventListener('change', () => updateSelectedText(locationCheckboxes, 'selected-locations', '选择地点')); }); document.querySelector('.select-all-loc').addEventListener('click', () => { document.querySelectorAll(locationCheckboxes).forEach(cb => cb.checked = true); updateSelectedText(locationCheckboxes, 'selected-locations', '选择地点'); }); document.querySelector('.deselect-all-loc').addEventListener('click', () => { document.querySelectorAll(locationCheckboxes).forEach(cb => cb.checked = false); updateSelectedText(locationCheckboxes, 'selected-locations', '选择地点'); }); // 行业筛选交互 const sectorCheckboxes = 'input[name="filter[sector_ids][]"]'; updateSelectedText(sectorCheckboxes, 'selected-sectors', '选择行业'); document.querySelectorAll(sectorCheckboxes).forEach(cb => { cb.addEventListener('change', () => updateSelectedText(sectorCheckboxes, 'selected-sectors', '选择行业')); }); document.querySelector('.select-all-sec').addEventListener('click', () => { document.querySelectorAll(sectorCheckboxes).forEach(cb => cb.checked = true); updateSelectedText(sectorCheckboxes, 'selected-sectors', '选择行业'); }); document.querySelector('.deselect-all-sec').addEventListener('click', () => { document.querySelectorAll(sectorCheckboxes).forEach(cb => cb.checked = false); updateSelectedText(sectorCheckboxes, 'selected-sectors', '选择行业'); }); });
关键说明
- 排版优化:用Bootstrap的
form-check类包裹复选框和标签,避免杂乱;下拉菜单设置固定宽度,保证布局规整。 - 交互增强:添加选中项文本显示,用户能直观看到已选内容;全选/取消全选按钮提升操作效率。
- 表单兼容性:保留
collection_check_boxes的参数提交逻辑,后端无需修改即可接收数组格式的筛选参数。 include_hidden: false:移除默认生成的隐藏空值输入框,避免无选中时提交空字符串数组(若需要兼容无选中场景可保留)。
内容的提问来源于stack exchange,提问作者trycoder
相关产品推荐
相关产品推荐

