You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript如何基于两个下拉菜单选中值筛选匹配的数组对象

问题核心错误与修复方案

核心错误点

  • 数组合并逻辑错误:concat是取两个数据集的并集,不是求同时满足两个条件的交集,导致所有匹配其中任意一个条件的结果都被加入了mainList
  • 筛选逻辑完全不符合需求:原filter逻辑是判断动作名称中是否包含器械值,且错误使用indexOf的返回值(indexOf返回-1代表未匹配,-1属于真值会被保留,导致几乎所有数据都通过筛选),同时完全没有对身体部位字段做匹配
  • 未排除下拉默认值的干扰:原判断条件d2.value && d1.value !== -1逻辑错误,无法正确识别用户是否选择了有效的选项
  • 数据请求逻辑不合理:每次仅更新一个对应类型的数据集,另一类数据集还保留着之前的选中结果,导致合并后的数据混乱

推荐修复方案(本地全量筛选,减少接口请求次数)

1. 调整下拉创建逻辑,给默认选项设置空值

function createDropdown(name, items) {
    const select = document.createElement("select"); 
    select.className = "selectMenu"
    select.name = name
    select.id = name
    for (let i = 0; i < items.length; i++) { 
        const item = items[i]; 
        const option = document.createElement("option"); 
        // 第一个默认选项value设为空,方便判断是否选中有效选项
        option.setAttribute("value", i === 0 ? "" : item); 
        option.innerHTML = item; 
        select.appendChild(option); 
    }
    exercises.appendChild(select); 

    // 下拉变化直接触发筛选
    select.addEventListener("change", function () {
        dataDiv.innerHTML = '';
        filterAndDisplay();
    })
}

2. 页面加载时初始化下拉+拉取全量动作数据

const dataDiv = document.getElementById("data")
let mainList = [] // 存储全量动作数据
const bodyparts = ["Body Parts", "back", "cardio", "chest", "lower arms", "lower legs", "neck", "shoulders", "upper arms", "upper legs", "waist"]
const equipment = ["Equipment", "assisted", "band", "barbell", "body weight", "cable", "dumbbell", "ez barbell", "hammer", "kettlebell", "leverage machine", "medicine ball", "resistance band", "roller", "rope", "smith machine", "tire", "trap bar", "weighted"]
const exercises = document.getElementById("exercises");

window.addEventListener("load", async function () {
    // 初始化两个下拉
    createDropdown("bodypart", bodyparts);
    createDropdown("equipment", equipment);
    // 拉取全量动作数据存储到本地
    const response = await fetch(`https://exercisedb.p.rapidapi.com/exercises`, {
        "method": "GET",
        "headers": {
            "x-rapidapi-host": "exercisedb.p.rapidapi.com",
            "x-rapidapi-key": "替换成你自己的apiKey"
        }
    })
    mainList = await response.json();
})

3. 新增筛选+渲染逻辑

function filterAndDisplay() {
    const selectedBodyPart = document.getElementById("bodypart").value;
    const selectedEquipment = document.getElementById("equipment").value;

    // 任意一个下拉未选有效选项,提示用户
    if (!selectedBodyPart || !selectedEquipment) {
        dataDiv.innerHTML = "<p>请同时选择训练部位和器械</p>";
        return;
    }

    // 同时匹配两个条件筛选
    const filteredList = mainList.filter(item => {
        return item.bodyPart === selectedBodyPart && item.equipment === selectedEquipment;
    })

    // 输出筛选结果到控制台+渲染到页面
    console.log(filteredList);
    filteredList.forEach(element => {
        const div = document.createElement("div");
        const p = document.createElement("p");
        p.innerHTML = element.name
        div.appendChild(p)
        div.className = "card"
        dataDiv.appendChild(div)
    });
}

4. 可删除的冗余代码

原来的getApiURL、mergeLists、旧的displayData函数都可以删除,不再需要。

可选方案(按需请求接口,减少数据返回量)

如果全量动作数据量过大不想一次性拉取,可以在两个下拉都选中有效选项后,先请求对应部位的动作列表,再在返回结果中筛选匹配器械的条目,逻辑和上面的筛选部分一致,只是数据来源改为接口返回的部位数据即可。

内容的提问来源于stack exchange,提问作者Dave

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 14:45:03