PHP渲染卡片列表时如何为每张卡片绑定独立进度条计时器
问题根因
两个核心bug导致功能异常:
- 公共定时器管理代码(
$.ii方法、_sI定时器存储数组)被放在卡片循环里重复输出,每渲染一张卡片就会覆盖之前定义的$.ii方法、重置定时器存储对象,导致之前注册的定时器无法被正常管理,出现重复执行、清理失效的问题。 - 改造时漏改了初始化读取本地存储的逻辑,所有卡片初始值都固定读
timer1_value这一个键的存储值,初始加载时所有进度条数值就已经一致。 - 额外小问题:PHP拼接class名时直接写裸的
timer,PHP会将其识别为未定义常量,虽然低版本PHP会自动转为字符串'timer',但会抛出警告,存在兼容风险。
正确实现方案
第一步:抽离全局公共代码
将定时器管理的公共逻辑抽离到页面公共位置(比如引入jQuery之后),全页面仅加载1次,绝对不能放到卡片循环中重复输出:
<script> var ar; $(document).ready(function(){ var _sI = []; $.ii = function(){ ar = arguments; if(ar.length == 3){ if(_sI[ar[0]] != undefined){ clearInterval(_sI[ar[0]].reg); } _sI[ar[0]] = { fn: ar[2], t: ar[1], reg: setInterval(ar[2], ar[1]) }; }else if(ar.length == 1){ clearInterval(_sI[ar[0]].reg); } } }); </script>
第二步:改造卡片循环输出逻辑
在PHP遍历数据库查询结果的循环中,仅输出当前卡片对应的进度条标签和独立的初始化逻辑,所有和卡片绑定的标识(class名、localStorage键、定时器ID)都用卡片唯一ID动态生成,不要写死固定值:
<?php // 以下为遍历数据库结果集的循环内代码 // 假设你用的是mysqli查询,循环结构类似 while($row = $result->fetch_assoc()){ ?> <progress class="timer<?= intval($row[0]) ?>" value="0" max="100"></progress> <script> $(document).ready(function () { // 绑定当前卡片的唯一标识,全部动态生成 const cardId = <?= intval($row[0]) ?>; const storageKey = `timer${cardId}_value`; const progressEl = $(`.timer${cardId}`); const timerSign = `t${cardId}`; // 读取当前卡片独立的存储值,不再读固定键 let initValue = Number(localStorage.getItem(storageKey) || 0); progressEl.val(initValue); // 注册当前卡片的独立定时器 $.ii(timerSign, 36000, function () { let currentVal = Number(progressEl.val()); if (currentVal < 100) { let newVal = currentVal + 1; progressEl.val(newVal); localStorage.setItem(storageKey, newVal); } else { localStorage.removeItem(storageKey); $.ii(timerSign); } }); }); </script> <?php // } 循环结束括号 ?>
可选优化
如果卡片数量较多,不建议给每个卡片单独嵌<script>标签,可以在循环时把所有卡片ID收集到一个PHP数组里,循环结束后一次性把ID列表输出为JS数组,统一初始化所有定时器,减少页面冗余代码,性能更好。
内容的提问来源于stack exchange,提问作者Dayreff
相关产品推荐
相关产品推荐

