Laravel8切换页面时JS倒计时重置及waktu未定义报错求助
问题原因
两个问题的根源分别是:
Uncaught ReferenceError: waktu is not defined报错:waktu被定义在$.get异步回调的局部作用域内,且$.get是异步执行,代码运行到计算deadline的位置时,回调还没执行,全局作用域下访问不到waktu变量就会报错。另外原代码里var waktu = $("#timer").html(topic);的写法本身逻辑错误,既没有id为timer的DOM元素,赋值拿到的还是jQuery对象不是数值。- 切换页面倒计时重置:传统页面跳转时会销毁当前页面的所有JS运行环境,内存中的变量全部清空,原代码每次页面加载都基于当前时间重新计算截止时间,自然会回到初始值重新计数。
修复步骤
1. 调整后端控制器逻辑
去掉从请求参数取timer值的逻辑,直接在后端固定初始倒计时时长,避免前端篡改参数作弊,把初始值直接传给模板:
public function show(Request $request, $id) { $datas = Q_Question::where('topic_id', '=', $id)->simplePaginate(1); $topic = Q_Topic::where('id', '=', $id)->first(); // 此处设置初始倒计时总分钟数,例如限制访问30分钟则填30,可按需修改 $topic->timer = 30; return view('qanswers.show', compact('datas', 'topic')); }
2. 修改Blade模板
在模板的<head>区域新增meta标签,用于把后端传的初始时长输出到前端,同时保留原有的倒计时DOM结构即可:
<meta name="initial-timer" content="{{ $topic->timer }}"> <!-- 原有倒计时DOM结构保持不变 --> <div class="col-md-2"> jam : <div id="clockdiv"> <div> <span class="days"></span> <div class="smalltext">Days</div> </div> <div> <span class="hours"></span> <div class="smalltext">Hours</div> </div> <div> <span class="minutes"></span> <div class="smalltext">Minutes</div> </div> <div> <span class="seconds"></span> <div class="smalltext">Seconds</div> </div> </div> </div>
3. 替换原有JS代码
删除原有无效的$.get请求逻辑,改用localStorage存储统一的截止时间戳,同域名下所有页面共享该值,从根源解决跨页面重置问题,同时修复变量作用域报错:
function getTimeRemaining(endtime) { const t = Date.parse(endtime) - Date.parse(new Date()); const seconds = Math.floor((t / 1000) % 60); const minutes = Math.floor((t / 1000 / 60) % 60); const hours = Math.floor((t / (1000 * 60 * 60)) % 24); const days = Math.floor(t / (1000 * 60 * 60 * 24)); return { 'total': t, 'days': days, 'hours': hours, 'minutes': minutes, 'seconds': seconds }; } function initializeClock(id, endtime) { const clock = document.getElementById(id); const daysSpan = clock.querySelector('.days'); const hoursSpan = clock.querySelector('.hours'); const minutesSpan = clock.querySelector('.minutes'); const secondsSpan = clock.querySelector('.seconds'); const timeinterval = setInterval(updateClock, 1000); function updateClock() { const t = getTimeRemaining(endtime); // 倒计时归0处理 if (t.total <= 0) { clearInterval(timeinterval); localStorage.removeItem('countdown_deadline'); // 此处可添加超时后的业务逻辑,例如跳转到超时提示页 // window.location.href = '/timeout'; daysSpan.innerHTML = 0; hoursSpan.innerHTML = '00'; minutesSpan.innerHTML = '00'; secondsSpan.innerHTML = '00'; return; } daysSpan.innerHTML = t.days; hoursSpan.innerHTML = ('0' + t.hours).slice(-2); minutesSpan.innerHTML = ('0' + t.minutes).slice(-2); secondsSpan.innerHTML = ('0' + t.seconds).slice(-2); } updateClock(); } document.addEventListener('DOMContentLoaded', function() { let deadline; // 优先读取本地存储的截止时间,存在则直接复用 const storedDeadline = localStorage.getItem('countdown_deadline'); if (storedDeadline) { deadline = new Date(Number(storedDeadline)); } else { // 无存储时读取初始时长计算截止时间,并存入本地存储 const initialMinutes = Number(document.querySelector('meta[name="initial-timer"]').content); deadline = new Date(Date.now() + initialMinutes * 60 * 1000); localStorage.setItem('countdown_deadline', deadline.getTime().toString()); } initializeClock('clockdiv', deadline); });
补充说明
localStorage数据持久化存储在浏览器本地,同域名下页面切换、刷新都不会丢失,因此倒计时会持续累计不会重置- 如果需要手动重置倒计时(例如用户主动退出访问、提交表单后),在对应触发逻辑中执行
localStorage.removeItem('countdown_deadline');即可 - 初始时长固定在后端返回,避免前端篡改参数延长访问时长,安全性更高
内容的提问来源于stack exchange,提问作者indahwati indahwati
相关产品推荐
相关产品推荐

