PHP+JavaScript实现多卡片独立倒计时的DOM获取异常问题
带独立计时器卡片渲染异常修复
问题现象
开发卡片倒计时功能时,已完成数据库设计可存储倒计时目标日期时间,使用$row[0]作为元素标识时页面仅能显示单个正常工作的计时器,无法实现每张卡片对应独立倒计时的效果。
已知数据库查询结果字段映射如下:
$row[0]:记录唯一ID$row[1]:序列号$row[2]:街道信息$row[3]:年$row[4]:月$row[5]:日$row[6]:时$row[7]:分$row[8]:秒
运行环境为PHP + Apache2。
问题根因
核心问题集中在DOM获取逻辑和前后端语法拼接上,共有4处直接导致异常的错误:
- 时间格式拼接错误:时分秒部分使用
-分隔分和秒,不符合标准时间字符串格式,JS的Date对象无法正确解析得到有效时间戳 - PHP语法使用错误:
document.getElementById(<?php $row[0] ?>)位置没有输出ID值,且参数未加字符串引号,JS无法识别为合法的ID选择器;最后输出p标签时使用单引号包裹字符串,单引号内的PHP变量不会被解析,所有p标签都会得到id为字面量$row[0]的重复属性,页面存在重复ID时getElementById只会匹配第一个元素 - 变量作用域污染:循环输出多张卡片时,每段内嵌JS都在全局作用域定义同名变量
x、countDownDate,后执行的脚本会覆盖前面的变量值,导致前面卡片的计时器全部失效 - 执行顺序错误:先执行JS计时器逻辑再输出目标p标签,JS运行时DOM节点还未渲染,会拿到空对象报错
修复后完整代码
<?php // 修正时间拼接格式,月日时分秒统一补前导零,用:分隔时分秒 $date = $row[3] . "-" . str_pad($row[4],2,"0",STR_PAD_LEFT) . "-" . str_pad($row[5],2,"0",STR_PAD_LEFT); $time = str_pad($row[6],2,"0",STR_PAD_LEFT) . ":" . str_pad($row[7],2,"0",STR_PAD_LEFT) . ":" . str_pad($row[8],2,"0",STR_PAD_LEFT); $date_today = $date . ' ' . $time; $cardId = $row[0]; ?> <!-- 先输出DOM元素,保证JS执行时节点已经存在 --> <p id="timer_<?php echo $cardId; ?>" style="font-size:18px;"></p> <script type="text/javascript"> // 用立即执行函数隔离作用域,避免循环输出时变量互相覆盖 (function(){ var targetTime = new Date("<?php echo $date_today; ?>").getTime(); var timerDom = document.getElementById("timer_<?php echo $cardId; ?>"); var timer = setInterval(function(){ var now = new Date().getTime(); var distance = targetTime - now; var hours = Math.floor((distance%(1000*60*60*24))/(1000*60*60)); var minutes = Math.floor((distance%(1000*60*60))/(1000*60)); var seconds = Math.floor((distance%(1000*60))/1000); timerDom.innerHTML = hours + "h " + minutes + "m " + seconds + "s "; if(distance < 0){ clearInterval(timer); timerDom.innerHTML = "COMPLETO"; } },1000); })(); </script>
关键修复说明
- 补全月、日、时、分、秒的前导零,避免出现
2024-1-2 3:4-5这类非法时间格式,保证JS时间解析逻辑在所有浏览器下稳定运行 - 调整DOM输出顺序,先渲染p标签再执行JS逻辑,避免JS执行时找不到节点的问题;给ID加
timer_前缀,规避纯数字ID在部分浏览器下的兼容问题 - 所有PHP变量输出位置补全
echo语法,修正单引号字符串不解析变量的问题,保证每个卡片的计时器节点都有全局唯一的ID - 用立即执行函数隔离每个计时器的作用域,每个定时器持有独立的目标时间、DOM引用和定时器ID,循环输出多张卡片时逻辑不会互相覆盖
内容的提问来源于stack exchange,提问作者Dayreff
相关产品推荐
相关产品推荐

