You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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秒等待期内点击新卡片时:

  1. 会立即清除所有未执行的翻回超时任务
  2. 之前的两张卡片会马上翻回原始状态
  3. 随后正常处理当前点击的卡片翻牌,不会出现多张卡片同时翻开的混乱情况

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 19:12:38