本文介绍一种基于 HTML dataset 属性与动态 DOM 操作的现代方案,替代硬编码多个计数变量,实现对任意数量同类型网格项(如 .grid-item)的独立点击计数与状态管理。
本文介绍一种基于 html `dataset` 属性与动态 dom 操作的现代方案,替代硬编码多个计数变量,实现对任意数量同类型网格项(如 `.grid-item`)的独立点击计数与状态管理。
在传统 jQuery 实现中(如原代码所示),开发者常为每个网格项(#grid1 到 #grid9)单独声明 clicks1 ~ clicks9 变量,并绑定独立事件处理器——这种方式不仅冗余、难以维护,更无法扩展至 100+ 图块。根本问题在于:全局变量无法区分点击来源,导致所有图块共享同一计数器。
✅ 正确思路:将状态内聚到每个 DOM 元素自身
利用 HTML5 的 dataset API,可为每个 <div class="grid-item"> 动态附加自描述状态属性,例如:
- data-count="0":标识图块序号(逻辑 ID)
- data-times-clicked="0":记录该图块被点击次数
这样,每个图块“自带计数器”,无需外部变量映射,天然支持无限扩展。
✅ 推荐实现(原生 JavaScript + 语义化结构)
<div class="grid-container"></div> <button id="addBtn">添加图块</button>
const get = query => [...document.querySelectorAll(query)];
const STARTING_GRID_COUNT = 9;
const gridContainer = get(".grid-container")[0];
const addBtn = get("#addBtn")[0];
// 点击处理器:从当前元素 dataset 读取并更新计数
const handleGridClick = (e) => {
const el = e.target;
const count = el.dataset.count;
const current = parseInt(el.dataset.timesClicked) || 0;
const next = current + 1;
el.dataset.timesClicked = next;
console.log(`图块 #${count} 已被点击 ${next} 次`);
// ✅ 可在此处扩展状态切换逻辑(如轮换背景图)
// 示例:3 状态循环(slika1 → slika2 → slika3 → slika1)
const cycle = ["slika1", "slika2", "slika3"];
const nextClass = cycle[next % 3];
// 移除旧状态类,添加新状态类
el.classList.remove(...cycle);
el.classList.add(nextClass);
};
// 创建单个图块
const createGridItem = () => {
const item = document.createElement("div");
item.className = "grid-item slika1"; // 默认初始状态
item.dataset.count = gridContainer.children.length;
item.dataset.timesClicked = "0";
item.textContent = gridContainer.children.length + 1;
item.addEventListener("click", handleGridClick);
gridContainer.appendChild(item);
};
// 初始化网格
for (let i = 0; i < STARTING_GRID_COUNT; i++) {
createGridItem();
}
// 支持动态扩容
addBtn.addEventListener("click", createGridItem);⚠️ 注意事项与最佳实践
- 避免 jQuery 依赖:原生 dataset 和 addEventListener 更轻量、兼容性好(IE11+),且无全局作用域污染风险;
- 状态与视图分离:dataset 存储原始数据,CSS 类(如 slika1/slika2)仅负责视觉表现,便于后期维护与主题切换;
- 性能友好:事件委托非必需(因图块静态或低频增删),直接绑定更直观;若图块极多(>1000),可改用事件委托 + e.target.matches('.grid-item');
- CSS 建议:使用 CSS Grid 替代浮动/inline-block,配合 place-items: center 简化居中逻辑(见下方样式示例):
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
padding: 12px;
}
.grid-item {
aspect-ratio: 1;
display: grid;
place-items: center;
font-size: 1.2rem;
cursor: pointer;
border: 1px solid #ccc;
transition: background-color 0.2s;
}
.grid-item:hover { background-color: #f5f5f5; }
/* 背景图类保持原样 */
.slika1 { background-image: url("/images/narava2.jpg"); }
.slika2 { background-image: url("/images/cat.jpg"); }
.slika3 { background-image: url("/images/food-spread.jpg"); }✅ 总结
通过将计数状态下沉至 DOM 元素的 dataset,配合函数式创建逻辑,我们彻底摆脱了“为每个图块写一个变量 + 一个事件监听器”的反模式。该方案简洁、可扩展、易测试——无论渲染 9 个还是 1000 个图块,核心逻辑零修改,真正实现「一次编写,无限复用」。

















