vue vite 序列帧动画报错了

vue
Uncaught (in promise) Error: Unknown variable dynamic import:at dynamic-import-helper:7:96at new Promise (<anonymous>)

变量形式的动态 import(),但 Vite 在运行时找不到这个变量对应的模块路径,所以 Promise 被 reject 了,浏览器就报了 Uncaught (in promise)。

修复后的代码

<template>
  <canvas
    ref="animationCanvas"
    class="animation_canvas"
    id="animation_canvas"
  ></canvas>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, nextTick, watch } from 'vue'

const props = defineProps({
  fileLength: {
    type: Number,
    default: 124
  },
  IntervalTime: {
    type: Number,
    default: 50
  },
  startAnimation: {
    type: Boolean,
    default: true
  }
})

const animationCanvas = ref(null)
const imagesLoaded = ref(false)
let stopPlayer = null

const imageModules = import.meta.glob('./bg/*.png', {
  eager: true,
  import: 'default'
})

const getImageSources = () => {
  const sources = []

  for (let i = 0; i <= props.fileLength; i++) {
    const path = `./bg/${i}.png`
    if (imageModules[path]) {
      sources.push(imageModules[path])
    } else {
      console.warn(`[animation] 图片不存在: ${path}`)
    }
  }

  return sources
}

const loadImages = (sources) => {
  return new Promise((resolve) => {
    let loadedImages = 0
    const numImages = sources.length
    const images = []

    if (!numImages) {
      resolve([])
      return
    }

    for (let i = 0; i < numImages; i++) {
      images[i] = new Image()
      images[i].onload = () => {
        loadedImages++
        if (loadedImages >= numImages) {
          resolve(images)
        }
      }
      images[i].onerror = () => {
        loadedImages++
        console.warn(`[animation] 加载失败: ${sources[i]}`)
        if (loadedImages >= numImages) {
          resolve(images.filter(Boolean))
        }
      }
      images[i].src = sources[i]
    }
  })
}

const playImages = (images, ctx, width, height, intervalTime) => {
  let imageNow = 0

  const drawCurrentFrame = () => {
    if (!images.length) return
    ctx.clearRect(0, 0, width, height)
    ctx.drawImage(images[imageNow], 0, 0, width, height)
    imageNow = (imageNow + 1) % images.length
  }

  drawCurrentFrame()

  const timer = setInterval(() => {
    if (!props.startAnimation) return
    drawCurrentFrame()
  }, intervalTime)

  return () => clearInterval(timer)
}

onMounted(async () => {
  await nextTick()

  const canvas = animationCanvas.value
  if (!canvas) return

  const ctx = canvas.getContext('2d')
  if (!ctx) {
    console.error('Failed to get canvas context')
    return
  }

  const width = canvas.offsetWidth
  const height = canvas.offsetHeight
  canvas.width = width
  canvas.height = height

  const sources = getImageSources()

  if (!sources.length) {
    console.error('未找到任何动画图片,请检查 ./bg/ 目录')
    return
  }

  const firstImgElement = new Image()
  firstImgElement.src = sources[0]
  firstImgElement.onload = () => {
    ctx.clearRect(0, 0, width, height)
    ctx.drawImage(firstImgElement, 0, 0, width, height)
  }

  const images = await loadImages(sources)
  imagesLoaded.value = true

  if (props.startAnimation && images.length) {
    stopPlayer = playImages(images, ctx, width, height, props.IntervalTime)
  }
})

watch(
  () => props.IntervalTime,
  () => {
    if (stopPlayer) {
      stopPlayer()
      stopPlayer = null
    }
  }
)

onBeforeUnmount(() => {
  if (stopPlayer) {
    stopPlayer()
    stopPlayer = null
  }
})
</script>

<style scoped>
.animation_canvas {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  z-index: -1;
}
</style>

喜欢