在使用 WordPress 和 Elementor 制作企业网站时,Loop Grid 常用于展示产品、案例、文章等循环内容。有些产品展示页面会在每张产品卡片的左上角添加一个醒目的数字,例如 1、2、3、4……,用于标识产品在当前列表中的排列顺序。
如果这些数字由人工填写,不仅维护麻烦,产品排序或列表内容发生变化时也容易出现编号错误。更合适的方式是让页面根据 Loop Grid 中每个循环项目的实际顺序自动生成编号。
本文以 Elementor Loop Grid 为例,介绍如何使用 JavaScript 实现自动编号,并讨论 CSS 计数器方案的局限,以及 AJAX 或动态筛选场景下需要注意的问题。
一、需求与页面结构
本例中使用以下 CSS 类:
| 元素 | CSS 类 | 作用 |
|---|---|---|
| 最外层 Loop Grid 容器 | .hzt-products1 |
定位需要编号的产品列表 |
| 每个循环项目 | .e-loop-item |
Elementor 输出的单个循环条目 |
| 序号容器 | .hzt-loop-number |
显示自动生成的数字 |
目标是:找到每个 .hzt-products1 容器,按照其中 .e-loop-item 的 DOM 顺序依次编号,并把结果写入对应的 .hzt-loop-number 元素。
例如,页面中有四个产品卡片,最终显示效果应为:
- 第一个产品:
1 - 第二个产品:
2 - 第三个产品:
3 - 第四个产品:
4
这里需要的是当前列表中的排列序号,而不是 WordPress 文章 ID。文章 ID 是数据库记录的标识,不能用于表示产品在当前列表中的位置。
二、为什么不直接使用 CSS 计数器?
CSS counter-reset、counter-increment 和 counter() 可以实现纯视觉编号,代码较少,不需要 JavaScript。但在 Elementor 的实际布局中,计数器依赖具体的 DOM 层级和 CSS 选择器。
例如:
- 计数器可能因为重置位置或层级不正确而显示异常;
- Loop Item 内的编号元素可能位于独立的 Elementor 包装容器中;
- 如果编号需要写入真实文本,而不是通过伪元素显示,CSS 计数器就不一定适用;
- AJAX 筛选、动态加载或重新渲染后,编号可能需要重新计算。
如果需求只是简单装饰,CSS 计数器仍然值得考虑;但如果希望明确地修改 .hzt-loop-number 的文本内容,JavaScript 会更直接。
三、基础实现:使用 JavaScript 自动编号
如果页面是普通的 Elementor Loop Grid,没有 AJAX 筛选或动态加载,可以使用以下代码:
document.addEventListener('DOMContentLoaded', function () {
document.querySelectorAll('.hzt-products1').forEach(function (container) {
container.querySelectorAll('.e-loop-item').forEach(function (item, index) {
const numberElement = item.querySelector('.hzt-loop-number');
if (numberElement) {
numberElement.innerText = index + 1;
}
});
});
});
代码说明
1. 等待 DOM 加载完成
document.addEventListener('DOMContentLoaded', function () {
// 编号逻辑
});
这样可以避免脚本执行时,页面中的 Loop Grid 元素尚未解析完成。
2. 查找指定的列表容器
document.querySelectorAll('.hzt-products1')
使用指定的外层类名,避免影响网站其他 Loop Grid。即使页面中存在多个 .hzt-products1 容器,代码也会分别处理。
3. 按顺序遍历循环项目
container.querySelectorAll('.e-loop-item').forEach(function (item, index) {
querySelectorAll() 按照 DOM 顺序返回匹配的元素。forEach() 的 index 从 0 开始,因此显示时需要加 1。
4. 更新序号文本
const numberElement = item.querySelector('.hzt-loop-number');
if (numberElement) {
numberElement.innerText = index + 1;
}
每个循环项目内部只查找自己的 .hzt-loop-number,然后修改其文本内容。如果某个项目没有该元素,代码会跳过它,不会因为找不到元素而报错。
四、支持 DOM 动态更新的版本
如果页面使用 AJAX 筛选、动态加载或其他会改变 Loop Grid DOM 结构的功能,初始编号可能在内容更新后失效。例如,筛选后的产品列表发生变化,或者 Elementor 重新生成了部分循环项目。
这种情况下,可以使用 MutationObserver 监听容器内部的 DOM 变化,并在发生变化时重新编号。
(function () {
function updateLoopNumbers() {
document.querySelectorAll('.hzt-products1').forEach(function (container) {
container.querySelectorAll('.e-loop-item').forEach(function (item, index) {
const numberElement = item.querySelector('.hzt-loop-number');
if (numberElement) {
numberElement.innerText = index + 1;
}
});
});
}
// 根据当前文档状态执行初始编号
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', updateLoopNumbers);
} else {
updateLoopNumbers();
}
// 监听已经存在的列表容器
document.querySelectorAll('.hzt-products1').forEach(function (container) {
const observer = new MutationObserver(function () {
updateLoopNumbers();
});
observer.observe(container, {
childList: true,
subtree: true
});
});
})();
MutationObserver 的作用
MutationObserver 是浏览器提供的 DOM 变化观察机制。上面的代码监听指定列表容器内部的子节点变化,包括嵌套元素的新增和删除。
当观察到变化时,updateLoopNumbers() 会重新遍历列表,让编号与当前 DOM 顺序保持一致。
使用时的注意事项
- 优先使用基础版本。 如果产品列表只在页面加载时渲染一次,没有必要增加 DOM 观察逻辑。
- 避免不必要的重复执行。 动态版本会在观察到子节点变化时重新编号。如果页面频繁修改 DOM,可以进一步使用防抖或合并更新来减少执行次数。
- 新容器需要单独处理。 上述观察器会绑定在脚本执行时已经存在的
.hzt-products1容器上。如果整个容器本身是之后才插入页面的,当前代码不会自动为新容器建立观察器,需要扩展观察范围。 - 分页不等于跨页连续编号。 这段代码按当前 DOM 中的项目编号。翻到下一页后,通常会从
1重新编号;若需要跨页连续编号,需要结合当前页码和每页数量计算偏移量。 - 不要把它当作数据库序号。 这里生成的是前端显示编号,不会修改 WordPress 文章 ID、数据库记录或查询排序。
五、如何在 Elementor 中部署?
可以把代码放在网站自定义 JavaScript、子主题脚本文件,或支持自定义代码的管理工具中。部署前确认以下几点:
- Loop Grid 最外层容器已设置 CSS 类
hzt-products1。 - Loop Item 模板中的编号元素已设置 CSS 类
hzt-loop-number。 .hzt-loop-number位于对应的.e-loop-item内部。- 如果网站启用了缓存或 JavaScript 延迟执行,修改后需要清理相关缓存并在前端实际页面测试。
- 检查桌面端、移动端以及筛选、分页等真实使用场景。
如果只需要编号,.hzt-loop-number 可以是普通的文本容器,例如 span 或 div。脚本负责填入数字,颜色、背景、尺寸和定位仍然交给 CSS 控制。
六、常见问题
1. 为什么编号显示为 0?
如果页面仍然显示 0,通常说明 JavaScript 没有执行、选择器没有匹配到预期元素,或其他脚本在之后覆盖了文本。可以在浏览器开发者工具中检查:
document.querySelectorAll('.hzt-products1').length
document.querySelectorAll('.hzt-products1 .e-loop-item').length
document.querySelectorAll('.hzt-products1 .hzt-loop-number').length
如果结果为 0,请先核对 Elementor 中填写的 CSS 类是否正确,以及这些元素是否已经渲染到当前页面。
2. 为什么每个产品都显示相同的数字?
应当在每个 .e-loop-item 内部查找对应的 .hzt-loop-number,并使用 index + 1 作为文本。如果把编号元素放在循环项目之外,或者选择器错误地始终命中同一个元素,就可能导致结果不符合预期。
3. AJAX 筛选后编号没有更新怎么办?
使用本文的动态版本监听 DOM 变化。但需要注意,并不是所有筛选插件都会通过修改现有 DOM 的方式更新内容;如果插件采用其他更新机制,或整个外层容器被替换,需要根据实际 DOM 更新方式调整监听范围,必要时在筛选完成事件中主动调用编号函数。
4. 编号可以从指定数字开始吗?
可以。例如,希望从 11 开始,只需将:
numberElement.innerText = index + 1;
改成:
numberElement.innerText = index + 11;
如果需要根据分页页码自动计算起始值,则应在此基础上增加分页偏移量逻辑。
七、总结
Elementor Loop Grid 的产品卡片需要显示序号时,最重要的是区分文章 ID和当前循环位置。
对于普通列表,使用 JavaScript 遍历 .hzt-products1 下的 .e-loop-item,再将 index + 1 写入 .hzt-loop-number,即可实现自动编号。对于 AJAX 筛选或动态加载页面,可以考虑使用 MutationObserver,但需要根据页面实际的 DOM 更新方式验证兼容性。
这种方法不需要为每个产品手动维护编号,也不会修改 WordPress 数据库,适合企业网站的产品展示、案例列表和其他 Elementor 循环布局。
本文由 好主题 原创整理,致力于分享实用的 WordPress 建站知识与主题开发经验。 我们专注于提供高质量的 WordPress企业主题 资源,帮助中小企业轻松构建专业网站。 转载请注明来源,并保留原文链接,感谢您的支持与理解。