
本文介绍使用原生 JavaScript 根据父容器的 data-difficulty 属性值,动态为指定数量的子元素(.difficulty-item)添加 active 类,无需 jQuery,简洁高效且兼容性良好。
本文介绍使用原生 javascript 根据父容器的 `data-difficulty` 属性值,动态为指定数量的子元素(`.difficulty-item`)添加 `active` 类,无需 jquery,简洁高效且兼容性良好。
在构建评分、难度选择或进度指示器等 UI 组件时,常需根据父级配置(如 data-difficulty="3")控制其内部子项的激活状态。以下方案完全基于现代原生 DOM API,语义清晰、性能可靠,适用于所有主流浏览器(IE11+ 需微调,但本例默认面向现代环境)。
✅ 核心实现逻辑
使用 document.querySelectorAll() 获取全部 .difficulty-wrapper 容器,遍历每个容器:
- 通过 wrapper.dataset.difficulty 提取 data-difficulty 值(自动转为字符串,需注意类型转换);
- 使用 || 0 提供安全默认值,避免 undefined 导致异常;
- 查询所有 .difficulty-item 子元素,并用扩展运算符 [...nodeList] 转为数组;
- 利用 .slice(0, difficulty) 截取前 N 个子项(N 即难度值),天然支持边界处理(如 difficulty=5 但只有 4 个子项时自动截断);
- 对筛选出的子项统一调用 classList.add('active')。
document.querySelectorAll('.difficulty-wrapper').forEach(wrapper => {
const difficulty = parseInt(wrapper.dataset.difficulty) || 0;
const items = [...wrapper.querySelectorAll('.difficulty-item')];
items.slice(0, difficulty).forEach(item => item.classList.add('active'));
});
? 关键优化说明:将 parseInt() 显式加入可确保数值安全转换(避免 "4" 被当作字符串参与 slice),比 Number() 或 + 更健壮;slice(0, n) 天然防越界,无需额外 Math.min(n, items.length) 判断。
? 示例样式(增强可视化)
配合以下 CSS,可直观呈现激活态变化(蓝色背景表示已激活):
.difficulty-wrapper {
display: flex;
gap: 2px;
}
.difficulty-wrapper:not(:last-child) {
margin-bottom: 2px;
}
.difficulty-item {
width: 48px;
height: 32px;
border-radius: 2px;
background-color: #ffeb3b; /* 浅黄 */
border: 1px solid #f44336; /* 红边 */
transition: background-color 0.2s ease;
}
.difficulty-item.active {
background-color: #2196f3; /* 激活蓝 */
}
⚠️ 注意事项与最佳实践
-
DOM 加载时机:确保脚本在 HTML 解析完成后再执行,推荐将代码置于 底部,或包裹在 DOMContentLoaded 事件中:
document.addEventListener('DOMContentLoaded', () => { // 上述逻辑 }); - 动态更新支持:若后续需响应式更新(如难度值变更),可封装为函数并配合 MutationObserver 或手动重执行;
- 无障碍友好:建议为 .difficulty-item.active 添加 aria-current="true" 属性,提升屏幕阅读器体验;
-
避免重复添加:如需切换状态(而非仅追加),应先清除旧 active 类:
items.forEach(item => item.classList.remove('active')); —— 再按新值重新添加。
该方案轻量、可维护性强,是替代 jQuery 的现代化实践范例,适用于各类基于数据属性驱动 UI 状态的场景。











