JavaScript模板字面量生成的多倒计时器显示相同时间且闪烁问题求助
问题原因
- 初始化逻辑错误:你将
initializeClock直接写在模板字符串的onload属性中,首先div元素本身不支持onload事件,其次模板渲染阶段会同步执行三次initializeClock,同时开启三个定时器。三个定时器每秒都会修改所有倒计时节点的内容,互相覆盖导致所有倒计时最终都显示最后一次调用传入的结束时间对应的剩余值,高频覆盖更新也直接导致了闪烁问题。 - 更新范围错误:每个
initializeClock对应的updateClock方法都会遍历页面内所有倒计时节点,而非只更新和当前结束时间绑定的对应节点,这是所有倒计时显示一致的核心原因。 - ID重复:你给所有倒计时容器设置了相同的
id="counter",id是页面唯一标识,重复id会导致DOM获取逻辑异常。
修复方案
- 移除模板中的onload绑定,渲染完所有节点后遍历posts数组,分别为每个倒计时绑定对应的定时器。
- 修改
initializeClock逻辑,每个定时器仅更新对应索引的倒计时节点,不要全局遍历所有节点。 - 将重复的id="counter"改为class="counter",避免DOM选择异常。
修复后完整代码
JS代码
const posts = [ { title: 'Countdown 1', endTime: 'oct 12 2021 22:10:59 GMT+0200' }, { title: 'Countdown 2', endTime: 'sep 30 2021 13:59:59 GMT+0200' }, { title: 'Countdown 3', endTime: 'sep 25 2021 16:59:59 GMT+0200' } ]; function getRemainingTime(endTime) { const total = Date.parse(endTime) - Date.parse(new Date()); const seconds = Math.floor((total / 1000) % 60); const minutes = Math.floor((total / 1000 / 60) % 60); const hours = Math.floor((total / (1000 * 60 * 60)) % 24); const days = Math.floor(total / (1000 * 60 * 60 * 24)); return { total, days, hours, minutes, seconds }; } // 新增index参数,标记当前要更新的倒计时索引 function initializeClock(endTime, index) { function updateClock() { const t = getRemainingTime(endTime); // 只操作当前索引对应的节点 const daysSpan = document.getElementsByClassName('di')[index]; const hoursSpan = document.getElementsByClassName('ho')[index]; const minutesSpan = document.getElementsByClassName('mi')[index]; const secondsSpan = document.getElementsByClassName('se')[index]; const counter = document.getElementsByClassName('counter')[index]; daysSpan.innerHTML = ('0' + t.days).slice(-2) + ' DAY(S)'; hoursSpan.innerHTML = ('0' + t.hours).slice(-2) + ' HR(S)'; minutesSpan.innerHTML = ('0' + t.minutes).slice(-2) + ' MIN(S)'; secondsSpan.innerHTML = ('0' + t.seconds).slice(-2) + ' SEC(S)'; if (t.total <= 0) { clearInterval(timeinterval); counter.innerHTML = "The countdown is over!" } } updateClock(); const timeinterval = setInterval(updateClock, 1000); } function postsItem(post) { // 移除onload,id改为class return `<section> <h2 class="article-ttitle">${post.title}</h2> <article> <div class="counter"> <span class="di"></span> <span class="ho"></span> <span class="mi"></span> <span class="se"></span> </div> </article> </section>` } document.getElementById('posts').innerHTML = `${posts.map(postsItem).join('')}` // 渲染完成后遍历初始化每个倒计时 posts.forEach((post, index) => { initializeClock(post.endTime, index) })
HTML代码
<body> <div id="posts"></div> </body>
内容的提问来源于stack exchange,提问作者Ramy Naciri
相关产品推荐
相关产品推荐

