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
相关产品推荐
相关产品推荐

