You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

自定义层级依赖筛选器开发技术求助(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

火山引擎 最新活动