使用localStorage实现游戏连续游玩天数递增功能故障求助
问题背景
我是一名小学老师,自学JavaScript仅数月,出于兴趣开发一款每日仅可游玩一次(采用UTC时区切换日期)的游戏。目前游戏大部分功能正常,但连续游玩天数(streak count)无法实现递增——当用户连续游玩时,天数始终卡在1;不过若间隔超过1天未游玩,天数可正常重置为0。
现有代码逻辑
表单提交监听逻辑
监听表单提交事件,判断本次游玩日期是否为当日,若是则将日期存入localStorage(datesAreSameDay函数在其他功能中可正常工作):
const formForStreak = document.querySelector('form'); const todayStreak = new Date().toISOString(); formForStreak.addEventListener('submit', function(){ const streakTime = new Date().toISOString; // 语法错误:缺少括号 const todayForStreak = new Date(todayStreak); if (datesAreSameDay(streakTime, todayForStreak)){ localStorage.setItem("streakLastGuessDate", streakTime.toISOString()) } else if (!datesAreSameDay(streakTime,todayForStreak)){ console.log("Do something here") } })
页面加载时的连续天数处理逻辑
从localStorage获取上次游玩日期和当前连续天数,定义breakStreak函数判断是否间隔超过1天;页面加载时执行判断,若超过1天则重置天数为0,否则递增天数并更新localStorage和页面显示:
// 创建变量存储上次游玩日期 - 从localStorage获取 const streakLastGuess = localStorage.getItem("streakLastGuessDate"); // 获取连续天数,不存在则设为0 let streakCount = localStorage.getItem("streakCount") || 0; // 判断是否中断连续天数(间隔超过1天) function breakStreak (date1, date2) { return date1.getUTCFullYear() > date2.getUTCFullYear() + 1 || date1.getUTCMonth() > date2.getUTCMonth() + 1 || date1.getUTCDate() > date2.getUTCDate() + 1; // 页面加载时执行逻辑 window.onload = function() { if (streakLastGuess){ const breakLastGuessTimeStreak = new Date(streakLastGuess); const todayToday = new Date(); if (breakStreak(todayToday, breakLastGuessTimeStreak)){ streakCount = 0; localStorage.setItem("myStreak", JSON.stringify(streakCount)); console.log("You broke your streak! Counter set to 0.") document.getElementById("streak").innerHTML = JSON.stringify(streakCount); } else { streakCount++; document.getElementById("streak").innerHTML = JSON.stringify(streakCount); localStorage.setItem("myStreak", JSON.stringify(streakCount)); console.log("Hurray, let's add one to your streak!"); } document.getElementById("streak").firstChild.nodeValue = streakCount; localStorage.setItem("myStreak", JSON.stringify(streakCount)); }};
排查思路与修复点
1. 修复表单提交的语法错误
表单提交代码中const streakTime = new Date().toISOString;缺少括号,应为new Date().toISOString(),否则streakTime是函数引用而非日期字符串,后续存储操作会失败,导致streakLastGuessDate无法正确写入localStorage。
2. 统一localStorage键名
你获取连续天数时用的键是streakCount,但存储时用的是myStreak,键名不统一会导致每次页面加载时streakCount始终拿到默认值0,因为streakCount从未被写入过。需要将所有存储/读取连续天数的操作统一使用同一个键(比如streakCount)。
3. 优化breakStreak的日期判断逻辑
当前函数的判断逻辑存在漏洞(比如跨月份的日期差判断不准确),正确的做法是通过计算UTC时间戳的差值来判断间隔天数:
function breakStreak(date1, date2) { // 转换为仅保留日期的UTC时间戳(去除时分秒干扰) const time1 = Date.UTC(date1.getUTCFullYear(), date1.getUTCMonth(), date1.getUTCDate()); const time2 = Date.UTC(date2.getUTCFullYear(), date2.getUTCMonth(), date2.getUTCDate()); // 计算天数差(毫秒转天:1000*60*60*24) const dayDiff = (time1 - time2) / (1000 * 60 * 60 * 24); // 间隔超过1天则中断连续天数 return dayDiff > 1; }
4. 调整页面加载逻辑的变量作用域
将streakLastGuess和streakCount的获取逻辑移到window.onload内部,确保每次页面加载都能拿到最新的localStorage值;同时增加“当天是否已游玩”的判断,避免用户刷新页面重复递增天数:
window.onload = function() { // 实时获取最新的localStorage数据 const streakLastGuess = localStorage.getItem("streakLastGuessDate"); let streakCount = parseInt(localStorage.getItem("streakCount")) || 0; if (streakLastGuess){ const breakLastGuessTimeStreak = new Date(streakLastGuess); const todayToday = new Date(); if (breakStreak(todayToday, breakLastGuessTimeStreak)){ streakCount = 0; console.log("You broke your streak! Counter set to 0.") } else { // 判断是否为不同日期,避免当天重复递增 const todayUTC = Date.UTC(todayToday.getUTCFullYear(), todayToday.getUTCMonth(), todayToday.getUTCDate()); const lastGuessUTC = Date.UTC(breakLastGuessTimeStreak.getUTCFullYear(), breakLastGuessTimeStreak.getUTCMonth(), breakLastGuessTimeStreak.getUTCDate()); if (todayUTC !== lastGuessUTC) { streakCount++; console.log("Hurray, let's add one to your streak!"); } } // 统一键名存储 localStorage.setItem("streakCount", streakCount); // 简化页面更新方式 document.getElementById("streak").textContent = streakCount; } else { // 首次游玩初始化天数为1 streakCount = 1; localStorage.setItem("streakCount", streakCount); document.getElementById("streak").textContent = streakCount; } };
5. 优化表单提交的日期存储
提交表单时直接存储YYYY-MM-DD格式的UTC日期字符串,避免时间部分干扰后续日期判断:
formForStreak.addEventListener('submit', function(e){ e.preventDefault(); // 阻止表单默认提交行为,避免页面刷新 // 获取仅保留日期的UTC字符串 const todayUTC = new Date().toISOString().split('T')[0]; localStorage.setItem("streakLastGuessDate", todayUTC); });
总结
核心问题是键名不统一和语法错误导致连续天数无法正确存储与读取,其次是日期判断逻辑不够严谨。按照上述修复点调整代码后,连续天数的递增功能应该可以正常工作。
内容的提问来源于stack exchange,提问作者daebird

