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

Vue应用中大量Canvas元素调用fillRect失效问题求助

10000个Canvas批量fillRect失效问题的解决方案

问题根源

同步循环操作大量DOM/Canvas元素时,会阻塞浏览器渲染线程,导致部分绘制操作被延迟或丢弃;同时重复的DOM查询、数组查询也会加剧性能开销,最终引发偶尔失效的情况。

具体解决方案

1. 分批异步处理,释放渲染线程

将10000个元素拆分为小批次,通过requestAnimationFrame分批执行,给浏览器留出渲染时间,避免单次操作阻塞线程:

const batchSize = 100; // 可根据实际性能调整批次大小
let currentKey = 1;

function processBatch() {
  const endKey = Math.min(currentKey + batchSize - 1, 10000);
  for (let key = currentKey; key <= endKey; key++) {
    const card = document.getElementById(key);
    if (!card) continue;
    
    if (!this.scratchedSet.has(key)) {
      const ctx = card.getContext('2d');
      ctx.fillStyle = '#b6b6b4';
      ctx.fillRect(0, 0, card.width, card.height);
      card.style.opacity = '1';
    } else {
      card.style.opacity = '1';
      card.style.outline = '2px solid #ef7200';
    }
  }
  currentKey = endKey + 1;
  if (currentKey <= 10000) {
    requestAnimationFrame(processBatch.bind(this));
  }
}

// 启动处理
processBatch.call(this);

2. 预缓存DOM元素与Canvas上下文

避免循环内重复执行getElementById和getContext,提前缓存所有需要操作的元素和上下文:

// 在mounted钩子中预缓存
mounted() {
  // 缓存所有canvas元素
  this.cards = Array.from({length:10000}, (_, i) => document.getElementById(i+1)).filter(Boolean);
  // 缓存所有canvas上下文
  this.canvasCtxs = this.cards.map(card => card.getContext('2d'));
  // 将scratchedValue转为Set,提升查询效率
  this.scratchedSet = new Set(this.scratched.scratchedValue);
}

// 处理逻辑改为使用缓存数据
let currentIndex = 0;
function processBatch() {
  const endIndex = Math.min(currentIndex + batchSize - 1, this.cards.length - 1);
  for (let i = currentIndex; i <= endIndex; i++) {
    const card = this.cards[i];
    const key = i + 1;
    
    if (!this.scratchedSet.has(key)) {
      const ctx = this.canvasCtxs[i];
      ctx.fillStyle = '#b6b6b4';
      ctx.fillRect(0, 0, card.width, card.height);
      card.style.opacity = '1';
    } else {
      card.style.opacity = '1';
      card.style.outline = '2px solid #ef7200';
    }
  }
  currentIndex = endIndex + 1;
  if (currentIndex < this.cards.length) {
    requestAnimationFrame(processBatch.bind(this));
  }
}

3. 优化数组查询性能

将scratchedValue数组转换为Set,把查询时间复杂度从O(n)降为O(1),大幅提升循环内的判断速度:

this.scratchedSet = new Set(this.scratched.scratchedValue);
// 后续判断用:this.scratchedSet.has(key)

4. 避免重复绘制

维护一个标记集合,记录已经完成填充的Canvas,避免重复执行fillRect操作:

data() {
  return {
    filledCards: new Set()
  }
}

// 处理时判断
if (!this.scratchedSet.has(key)) {
  if (!this.filledCards.has(key)) {
    const ctx = this.canvasCtxs[i];
    ctx.fillStyle = '#b6b6b4';
    ctx.fillRect(0, 0, card.width, card.height);
    this.filledCards.add(key);
  }
  card.style.opacity = '1';
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 19:01:12