自定义层级依赖筛选器开发技术求助(JavaScript)
按钮式层级筛选器解决方案(JavaScript实现)
我来帮你搞定这个层级依赖的按钮式筛选器问题!之前用<select>能实现的逻辑,换成按钮样式完全可以做到,核心是用数据结构关联各层级选项,再通过事件监听更新UI状态。
第一步:定义层级关联数据
首先我们需要把类别、宽度、轮廓的对应关系用对象存起来,这样后续选择时能快速找到对应选项:
// 存储各筛选层级的关联关系,可根据实际需求扩展 const filterRelations = { "Passeio": { defaultWidth: "500", widthOptions: { "500": { defaultPerfil: "01", perfilList: ["01", "02"] }, "505": { defaultPerfil: "02", perfilList: ["02", "03"] } } }, "SUV/Pickup/4x4": { defaultWidth: "510", widthOptions: { "510": { defaultPerfil: "03", perfilList: ["01", "03"] }, "515": { defaultPerfil: "01", perfilList: ["02", "03"] } } }, "Van e Utilitário": { defaultWidth: "505", widthOptions: { "505": { defaultPerfil: "01", perfilList: ["01", "03"] } } }, "Caminhão e Carga": { defaultWidth: "515", widthOptions: { "515": { defaultPerfil: "03", perfilList: ["02", "03"] } } } };
第二步:重构通用函数减少重复
把重复的打开筛选框逻辑合并成一个通用函数,避免冗余代码:
// 通用打开/关闭筛选框函数 function toggleFilterBox(filterType) { const box = document.querySelector(`.box__${filterType}`); box.style.display = box.style.display === 'flex' ? 'none' : 'flex'; }
第三步:实现层级联动逻辑
接下来写核心的选择事件处理函数,分别处理类别、宽度的选择后UI更新:
1. 类别选择后的宽度更新
function handleCategoriaSelect(btn) { // 更新类别显示文本 document.querySelector('.valueCategoria').textContent = btn.value; // 获取当前类别的关联数据 const categoriaData = filterRelations[btn.value]; if (!categoriaData) return; const larguraBox = document.querySelector('.box__largura'); const larguraValue = document.querySelector('.valueLargura'); const larguraButtons = larguraBox.querySelectorAll('.button'); // 重置宽度按钮状态 larguraButtons.forEach(button => { button.classList.remove('is-checked'); // 只显示当前类别支持的宽度选项 button.style.display = categoriaData.widthOptions.hasOwnProperty(button.value) ? 'inline-block' : 'none'; }); // 设置默认宽度并触发宽度选择逻辑 const defaultWidthBtn = larguraBox.querySelector(`[value="${categoriaData.defaultWidth}"]`); if (defaultWidthBtn) { defaultWidthBtn.classList.add('is-checked'); larguraValue.textContent = categoriaData.defaultWidth; handleLarguraSelect(defaultWidthBtn); } else { larguraValue.textContent = 'Selecionar largura'; resetPerfilFilter(); } }
2. 宽度选择后的轮廓更新
function handleLarguraSelect(btn) { document.querySelector('.valueLargura').textContent = btn.value; // 获取当前选中的类别 const selectedCategoria = document.querySelector('.valueCategoria').textContent; if (selectedCategoria === 'Selecionar categoria') return; const widthData = filterRelations[selectedCategoria].widthOptions[btn.value]; if (!widthData) return; const perfilBox = document.querySelector('.box__perfil'); const perfilValue = document.querySelector('.valuePerfil'); const perfilButtons = perfilBox.querySelectorAll('.button'); // 重置轮廓按钮状态 perfilButtons.forEach(button => { button.classList.remove('is-checked'); // 只显示当前宽度支持的轮廓选项 button.style.display = widthData.perfilList.includes(button.value) ? 'inline-block' : 'none'; }); // 设置默认轮廓 const defaultPerfilBtn = perfilBox.querySelector(`[value="${widthData.defaultPerfil}"]`); if (defaultPerfilBtn) { defaultPerfilBtn.classList.add('is-checked'); perfilValue.textContent = widthData.defaultPerfil; } else { perfilValue.textContent = 'Selecionar perfil'; } } // 重置轮廓筛选器状态 function resetPerfilFilter() { const perfilBox = document.querySelector('.box__perfil'); const perfilValue = document.querySelector('.valuePerfil'); const perfilButtons = perfilBox.querySelectorAll('.button'); perfilButtons.forEach(button => { button.classList.remove('is-checked'); button.style.display = 'none'; }); perfilValue.textContent = 'Selecionar perfil'; }
第四步:更新HTML事件绑定
把原来的onclick事件替换成我们新的函数:
<!-- 类别筛选部分 --> <div class="selecionar" onclick="toggleFilterBox('categoria')"> <p class="valueCategoria">Selecionar categoria</p> </div> <div class="button-group js-radio-button-group box__categoria" data-filter-group="color"> <button id="categoria_carro" class="button" data-filter=".red" value="Passeio" onclick="handleCategoriaSelect(this)">Passeio </button> <button class="button" data-filter=".blue" value="SUV/Pickup/4x4" onclick="handleCategoriaSelect(this)">SUV/Pickup/4x4 </button> <button class="button" data-filter=".yellow" value="Van e Utilitário" onclick="handleCategoriaSelect(this)">Van e Utilitário </button> <button class="button" data-filter=".yellow" value="Caminhão e Carga" onclick="handleCategoriaSelect(this)">Caminhão e Carga </button> </div> <!-- 宽度筛选部分 --> <div class="selecionar" onclick="toggleFilterBox('largura')"> <p class="valueLargura">Selecionar largura</p> </div> <div class="button-group js-radio-button-group box__largura" data-filter-group="size" id="largura_carro"> <button class="button" data-filter="" value="500" onclick="handleLarguraSelect(this)"> 500 </button> <button class="button" data-filter=".small" value="505" onclick="handleLarguraSelect(this)">505 </button> <button class="button" data-filter=".wide" value="510" onclick="handleLarguraSelect(this)">510 </button> <button class="button" data-filter=".big" value="515" onclick="handleLarguraSelect(this)">515 </button> </div> <!-- 轮廓和轮圈部分同理替换toggleFilterBox函数 --> <div class="selecionar" onclick="toggleFilterBox('perfil')">...</div> <div class="selecionar" onclick="toggleFilterBox('aro')">...</div>
第五步:初始化页面状态
页面加载时,把未选择状态下的宽度、轮廓按钮隐藏:
window.addEventListener('load', () => { // 初始隐藏宽度按钮 document.querySelectorAll('.box__largura .button').forEach(btn => btn.style.display = 'none'); // 初始隐藏轮廓按钮 resetPerfilFilter(); });
这样一套逻辑下来,就能实现你要的层级依赖效果:选择类别后自动填充对应默认宽度,选择宽度后自动显示对应轮廓选项,完全适配按钮式筛选的样式需求。
内容的提问来源于stack exchange,提问作者Kaio Almeida




