
本文介绍如何基于商品数组的 `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免费学习笔记(深入)”;











