JavaScript多类别商品筛选功能实现问题求助
多类别商品筛选功能修复方案
需求回顾
- 默认状态下所有商品卡片均激活显示
- 点击按钮可切换对应类别的显示/隐藏状态
- 选中多个按钮时,仅展示同时包含所有选中类别的商品卡片
修复后的完整代码
let products = { data: [ { productName: "Fantasy", heart: "./icons/heart.svg", heartCount: 2547, category: "Salmon, Shrimp", content: "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.", picture: "./images/pexels-diego-pontes-901015-2323391.jpg", }, { productName: "Spring", heart: "./icons/heart.svg", heartCount: 2547, category: "Veggie", content: "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.", picture: "./images/pexels-pixabay-357756.jpg", }, { productName: "Rainbow", heart: "./icons/heart.svg", heartCount: 2547, category: "Salmon, Tuna, Unagi", content: "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.", picture: "./images/pexels-freestockpro-3147493.jpg", }, { productName: "Unique", heart: "./icons/heart.svg", heartCount: 2547, category: "Salmon, Tuna, Unagi, Shrimp", content: "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.", picture: "./images/pexels-photo-248444.webp", }, { productName: "Perfection", heart: "./icons/heart.svg", heartCount: 2547, category: "Salmon", content: "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.", picture: "./images/pexels-isabella-mendes-107313-858501.jpg", }, { productName: "Style", heart: "./icons/heart.svg", heartCount: 2547, category: "Salmon, Tuna, Unagi, Shrimp", content: "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.", picture: "./images/pexels-rajesh-tp-749235-2098143.jpg", }, { productName: "Dreamy", heart: "./icons/heart.svg", heartCount: 2547, category: "Salmon", content: "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.", picture: "./images/pexels-viniciusbenedit-3620705.jpg", }, { productName: "Spicy", heart: "./icons/heart.svg", heartCount: 2547, category: "Shrimp", content: "Lorem ipsum dolor sit amet, eu mei posse possim atomorum, vix cu fabellas assueverit. Vel ad option partiendo maiestatis, nec affert appetere te, his.", picture: "./images/pexels-catscoming-699544.jpg", }, ], }; // 生成商品卡片 for (let i of products.data) { let card = document.createElement("div"); card.classList.add("card"); // 图片容器 let imgContainer = document.createElement("div"); imgContainer.classList.add("image-container"); let image = document.createElement("img"); image.classList.add("product-img"); image.setAttribute("src", i.picture); imgContainer.appendChild(image); card.appendChild(imgContainer); document.getElementById("products").appendChild(card); // 存储卡片的类别数组(预处理,避免重复解析) card.dataset.categories = JSON.stringify( i.category.split(",").map(cat => cat.trim()) ); image.addEventListener("error", () => { image.style.display = "none"; image.parentNode.style.backgroundColor = "#d9d9d9"; }); // 内容区域 let content = document.createElement("div"); content.classList.add("content"); card.appendChild(content); // 标题和点赞区 let contentHead = document.createElement("div"); contentHead.classList.add("contentHead"); let productTitle = document.createElement("h2"); productTitle.classList.add("productTitle"); productTitle.innerText = i.productName; let likesSection = document.createElement("div"); likesSection.classList.add("likesSection"); let likesIcon = document.createElement("img"); likesIcon.setAttribute("src", "./icons/heart.svg"); likesIcon.classList.add("likesIcon"); let likesCount = document.createElement("p"); likesCount.classList.add("likeCount"); likesCount.innerText = i.heartCount; content.appendChild(contentHead); contentHead.appendChild(productTitle); contentHead.appendChild(likesSection); likesSection.appendChild(likesIcon); likesSection.appendChild(likesCount); likesIcon.addEventListener("error", () => { likesIcon.setAttribute( "src", "https://upload.wikimedia.org/wikipedia/commons/f/f1/Heart_coraz%C3%B3n.svg" ); }); // 分隔线 let line = document.createElement("hr"); line.classList.add("product-line"); content.appendChild(line); // 类别显示 let itemCategory = document.createElement("p"); itemCategory.classList.add("item-category"); itemCategory.innerText = i.category; content.appendChild(itemCategory); // 描述 let itemDescription = document.createElement("p"); itemDescription.classList.add("itemDescription"); itemDescription.innerText = i.content; content.appendChild(itemDescription); // 查看更多 let readMore = document.createElement("p"); readMore.classList.add("readMore"); readMore.innerText = "Read more >>>"; content.appendChild(readMore); } // 筛选逻辑 let buttons = document.querySelectorAll(".category-button"); let cards = document.querySelectorAll(".card"); let selectedCategories = new Set(); // 用Set存储选中的类别,自动去重 // 统一的筛选函数 function filterProducts() { cards.forEach(card => { const cardCategories = JSON.parse(card.dataset.categories); // 无选中类别时显示所有卡片 if (selectedCategories.size === 0) { card.classList.remove("inactive-card"); return; } // 检查卡片是否包含所有选中的类别 const hasAllCategories = [...selectedCategories].every(cat => cardCategories.includes(cat) ); if (hasAllCategories) { card.classList.remove("inactive-card"); } else { card.classList.add("inactive-card"); } }); } // 绑定按钮点击事件 buttons.forEach(button => { button.addEventListener("click", () => { const category = button.innerText.trim(); button.classList.toggle("active-button"); // 更新选中类别集合 if (button.classList.contains("active-button")) { selectedCategories.add(category); } else { selectedCategories.delete(category); } // 执行筛选 filterProducts(); }); });
关键修改说明
- 预处理卡片类别:生成卡片时,将类别解析为数组并存储在
dataset.categories中,避免每次筛选重复解析字符串,提升性能。 - 用Set管理选中类别:自动去重,简化添加/删除操作。
- 重构筛选逻辑:
- 无选中按钮时直接显示所有卡片
- 使用
every()方法检查卡片是否包含所有选中类别,完全匹配需求中的“多类别交集筛选”
- 避免重复绑定事件:移除原代码中嵌套的按钮事件绑定逻辑,改为单次绑定,避免重复触发问题。
内容的提问来源于stack exchange,提问作者Alena Chuyankova
相关产品推荐
相关产品推荐

