Vue3记忆游戏无法清除setTimeout问题求助
Vue3 记忆游戏:解决超时未结束时点击卡片的翻牌冲突问题
问题核心
当前代码存在两个关键漏洞:
- 调用
unflip时,两次调用会覆盖同一个timeoutId,导致只能清除最后一个超时任务,之前的卡片翻回操作依然会执行 - 无状态锁机制,在等待卡片翻回的1.5秒内允许连续点击,导致多张卡片同时处于翻开状态
解决方案
1. 新增核心状态变量
添加两个关键状态控制逻辑:
isWaiting:标记当前是否处于等待卡片翻回的状态,避免重复触发无效点击timeoutIds:用数组存储所有未执行的超时ID,确保能一次性清除所有待执行的翻回操作
2. 重构核心方法
修改flipCard、unflip和compare方法,确保状态流转逻辑正确:
import { ref } from 'vue'; // 原有状态变量 const clicksNumber = ref(0); const comparedCards = ref([]); const found = ref([]); const notFound = ref([]); // 新增:标记是否处于等待翻回状态 const isWaiting = ref(false); // 新增:存储所有超时ID,避免单个ID被覆盖 const timeoutIds = ref([]); // 翻牌方法 function flipCard(card) { // 跳过已翻开或已匹配成功的卡片 if (card.isFlipped || found.value.includes(card)) return; // 如果正在等待翻回,先终止所有未完成的超时任务 if (isWaiting.value) { // 清除所有待执行的翻回超时 timeoutIds.value.forEach(id => clearTimeout(id)); timeoutIds.value = []; // 立即翻回之前的两张卡片 comparedCards.value.forEach(c => c.isFlipped = false); // 重置等待状态和待比较数组 isWaiting.value = false; comparedCards.value = []; } // 执行当前卡片翻牌 card.isFlipped = true; clicksNumber.value += 1; comparedCards.value.push(card); // 凑齐两张卡片,执行比较逻辑 if (comparedCards.value.length === 2) { compare(comparedCards.value[0], comparedCards.value[1]); } } // 翻回卡片方法,改为存储超时ID到数组 function unflip(card) { const id = setTimeout(() => { card.isFlipped = false; // 超时任务执行后,从数组中移除对应ID timeoutIds.value = timeoutIds.value.filter(tId => tId !== id); // 所有超时任务执行完毕后,重置等待状态 if (timeoutIds.value.length === 0) { isWaiting.value = false; } }, 1500); timeoutIds.value.push(id); } // 卡片比较方法 function compare(a, b) { // 标记进入等待状态 isWaiting.value = true; if (a.image === b.image) { found.value.push(a, b); // 更新未匹配卡片数组 notFound.value = notFound.value.filter(item => !found.value.includes(item)); // 匹配成功,直接重置等待状态 isWaiting.value = false; } else { // 不匹配,执行翻回逻辑 comparedCards.value.forEach(card => unflip(card)); } // 清空待比较卡片数组 comparedCards.value = []; }
关键改动说明
isWaiting状态锁:在等待卡片翻回的阶段,阻止无效重复点击;触发新点击时,先终止之前的未完成操作,再处理当前请求timeoutIds数组:解决了单个timeoutId被覆盖的问题,确保所有待执行的翻回超时任务都能被彻底清除flipCard前置拦截:直接跳过已翻开或已匹配的卡片,避免无意义操作;同时在等待状态触发时,立即修正之前的卡片状态
效果验证
现在在1.5秒等待期内点击新卡片时:
- 会立即清除所有未执行的翻回超时任务
- 之前的两张卡片会马上翻回原始状态
- 随后正常处理当前点击的卡片翻牌,不会出现多张卡片同时翻开的混乱情况
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

