
本文介绍如何基于商品数组的 `gen` 属性(如 `”mas”`、`”fem”`、`”inf”`)实现点击按钮实时筛选并重新渲染 html 商品卡片,避免重复插入、确保 dom 状态可控。
在构建动态商品目录时,仅靠 insertAdjacenthtml 逐个追加元素会导致多次点击筛选按钮后内容不断叠加,造成重复渲染与状态混乱。正确的做法是:统一管理数据源,按需生成完整 HTML 片段,并一次性替换容器内容。这不仅提升可维护性,也保证了视图与数据的一致性。
✅ 推荐实现方案:showProducts() + Filter()
首先,将原 addItem() 函数重构为更语义化的 showProducts() —— 它接收一个商品数组,清空目标容器,并用 .map() 生成所有卡片 HTML,最后通过 innerHTML 批量写入:
function showProducts(prods) { const container = document.getElementById("main__prods"); if (!container) return; const htmlString = prods.map(prod => ` <div class="col" style="margin-bottom: 1rem;"> <div class="card card__team h-100"> <div style="text-align: center;"> @@##@@ </div> <div class="card-body"> <div class="title__card"><span>${prod.title.slice(0, 30)}</span></div> <div class="subtitle__card"><span>${prod.Origen}</span></div> <p class="card-text" style="text-align: justify;">${prod.description} ...</p> </div> <div style="text-align:right; margin-top:0;"> <button type="button" class="btn btn-warning btn-producto" data-bs-toggle="modal" data-bs-target="#exampleModal${prod.id}"> Ver más <svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" fill="currentColor" class="bi bi-caret-down-fill" viewBox="0 0 16 16"> <path d="M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z"/> </svg> </button> </div> <!-- Modal HTML(同原逻辑,此处省略以保持简洁;实际使用中请保留完整结构) --> <div class="modal fade" id="exampleModal${prod.id}" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true"> <!-- 模态框完整内容(建议提取为独立函数或模板字符串复用) --> </div> </div> </div> `).join(''); container.innerHTML = htmlString; }
? 注意:为保障可读性与可维护性,建议将模态框(Modal)HTML 提取为单独模板函数(如 generateModalHTML(prod)),避免在 map 中嵌套过长字符串。
接着,为每个筛选按钮绑定事件监听器,使用 Array.prototype.filter() 精准匹配对应性别分组:
const filt_mas = document.getElementById("filt_mas"); const filt_fem = document.getElementById("filt_fem"); const filt_inf = document.getElementById("filt_inf"); // 初始加载全部商品 showProducts(prod1); // 绑定筛选事件 filt_mas.addEventListener("click", () => showProducts(prod1.filter(p => p.gen === "mas"))); filt_fem.addEventListener("click", () => showProducts(prod1.filter(p => p.gen === "fem"))); filt_inf.addEventListener("click", () => showProducts(prod1.filter(p => p.gen === "inf")));
⚠️ 关键注意事项
- 避免 insertAdjacentHTML 累加:原 addItem() 使用 beforeend 不断追加,导致多次筛选后 DOM 膨胀。innerHTML 替换是更可控的方式。
- 属性名一致性检查:示例数据中字段为 gen: “mas”,但问题描述中误写为 Gen:”more”。请确保 js 对象属性名(gen)与筛选条件(”mas” / “fem” / “inf”)严格一致,区分大小写。
- 性能优化提示:若商品量极大(>500 条),可考虑虚拟滚动或分页;当前方案适用于中小型目录(
- 无障碍与 seo 友好性:服务端渲染或静态生成更适合 SEO;纯客户端筛选需确保初始 HTML 包含有意义的占位内容或骨架屏。
✅ 总结
通过将“渲染逻辑”与“筛选逻辑”解耦 —— showProducts() 负责视图输出,filter() 负责数据处理 —— 我们实现了清晰、健壮且易于扩展的商品筛选功能。配合 bootstrap Modal 的复用结构与语义化 DOM 操作,该方案兼顾开发效率与用户体验,是前端商品目录交互的经典实践模式。
立即学习“Java免费学习笔记(深入)”;