03月27, 2025

Vue3+Vite 动态引入图片打包后生产环境不显示记录

Vue3+vite 项目中动态引入图片(非 public 目录)

今天在做项目的时候,使用动态路由配置,发现在 vue3+vite 项目中,动态引入图片,在开发环境中的时候,图片可以正常显示,但是打包构建后,部署生产找不到图片的,经过一番搜索,找到了解决方法,如下:

首先模版中的代码:

<template>
  <div class="eggs-con">
    <router-link
      v-for="(dataEgg, index) in dataEggs"
      :key="dataEgg.id"
      :to="{ name: 'eggs', params: { eggType: dataEgg.type } }"
    >
      {{ dataEgg.name }}
      <el-divider v-if="index !== dataEggs.length - 1" direction="vertical" />
    </router-link>

    <div v-if="!dataEgg">
      <h1>查无此蛋</h1>
    </div>
    <div v-else>
      <h1>{{ dataEgg.name }}</h1>
      <p>{{ dataEgg.description }}</p>
      <p>{{ dataEgg.flavour }}</p>

      <!-- 开发环境可以正常的显示,打包后无法正常预览 -->
      <img :src="`../../src/assets/images/${dataEgg.image}`" alt="" />

      <h2>import.meta.glob (动态导入)</h2>
      <img :src="imageSrc" v-if="imageSrc" />

      <br />
      <!-- <img :src="picture.default" alt=""> -->

      <h2>使用计算属性方式:(new URL)</h2>
      <img :src="imageSrcCom" alt="" />
    </div>
  </div>
</template>

之前用 vue2 版本的时候,使用的是require来引入图片,打包构建工具是webpack,但是现在使用的是vite构建,所以需要使用import.meta.glob来引入图片,并且需要使用new URL来获取图片的路径. vitewebpack 的核心差别还是挺大的,在 vite 中并没有这样的包。

开发环境截图

开发环境截图

glob 导入 动态引入图片

Vite 支持使用特殊的 import.meta.glob 函数从文件系统导入多个模块(该方式为异步加载模块形式),该函数接收一个匹配模块文件的通配符,返回一个对象,其中键是文件路径,值是可以导入相应模块的函数。

其中,data.json 文件中的内容如下:

[
  {
    "id": 1,
    "name": "鸡蛋",
    "type": "chicken-egg",
    "image": "chicken-egg.jpeg",
    "description": "又名鸡卵、鸡子,是母鸡所产的卵",
    "flavour": "味甘,性平,无毒(煮熟后)"
  },
  {
    "id": 2,
    "name": "鸭蛋",
    "type": "duck-egg",
    "image": "duck-egg.jpeg",
    "description": "又名鸭子、鸭卵、太平、鸭春、青皮等,为鸭科动物家鸭的卵,受精卵可孵化成小鸭",
    "flavour": "性涼、味甘"
  },
  {
    "id": 3,
    "name": "鹅蛋",
    "type": "goose-egg",
    "image": "goose-egg.jpeg",
    "description": "家禽鹅生下的卵",
    "flavour": "有些油"
  },
  {
    "id": 4,
    "name": "鹌鹑蛋",
    "type": "quail-egg",
    "image": "quail-egg.jpeg",
    "description": "鵪鶉所產的卵,蛋殼表面帶有棕褐色斑點",
    "flavour": "味甘、性平"
  },
  {
    "id": 5,
    "name": "笨蛋",
    "type": "dumb-egg",
    "image": "dumb-egg.jpeg",
    "description": "我才不是笨蛋",
    "flavour": "没吃过"
  }
]

生产环境截图

生产环境截图

逻辑部分 JS 代码(setup 语法糖)

import { ref, computed, watch, watchEffect } from 'vue';
import dataEggs from '../src/data.json';

const imageSrc = ref('');

const eggType = computed(() => route.params.eggType);
const dataEgg = computed(() =>
  dataEggs.find((egg) => egg.type === eggType.value)
);

// 方式1: // 使用 import.meta.glob 动态导入图片 不配置  { eager: true }
const images = import.meta.glob('../src/assets/images/*.jpeg');

watchEffect(async () => {
  if (dataEgg.value && dataEgg.value.image) {
    const imagePath = `../src/assets/images/${dataEgg.value.image}`;
    const imageModule = images[imagePath];
    if (imageModule) {
      try {
        const img = await imageModule();
        imageSrc.value = img.default;
      } catch (error) {
        console.error('Image not found:', dataEgg.value.image, error);
        imageSrc.value = '';
      }
    } else {
      console.error('Image not found:', dataEgg.value.image);
      imageSrc.value = '';
    }
  } else {
    imageSrc.value = '';
  }
});

以上这种方式匹配到的文件默认是懒加载的, 通过动态导入实现,并会在构建时分离为独立的 chunk 文件。如果你倾向于直接引入(同步加载使用)所有的模块,你可以传入 { eager: true } 作为第二个参数`.

// ...
// 省略导入相关文件

// 方式1: // 使用 import.meta.glob 动态导入图片 配置 { eager: true }
const images = import.meta.glob('../src/assets/images/*.jpeg', { eager: true });

watchEffect(() => {
  if (dataEgg.value && dataEgg.value.image) {
    const imagePath = `../src/assets/images/${dataEgg.value.image}`;
    const imageModule = images[imagePath];
    if (imageModule) {
      // console.log('imageModule.default', imageModule.default);
      imageSrc.value = imageModule.default;
    } else {
      console.error('Image not found:', dataEgg.value.image);
      imageSrc.value = '';
    }
  } else {
    imageSrc.value = '';
  }
});

使用 new URL() 的方法进行动态导入

在 Vue 中,如果你需要使用动态导入图片,你可以使用 new URL() 方法来获取图片的路径。

// ...
// 省略导入相关文件

const imageSrcCom = computed(() => {
  if (dataEgg.value && dataEgg.value.image) {
    try {
      return new URL(
        `../src/assets/images/${dataEgg.value.image}`,
        import.meta.url
      ).href;
    } catch (e) {
      console.error('Image not found:', e);
      return '';
    }
  }
  return '';
});

new URL() 方法中,import.meta.url 是一个特殊的变量,它表示当前模块的 URL。 在 vue3+vite的项目中,如果需要动态的导入图片,可以使用上面介绍的方法,防止在开发环境中好好的,打包构建后,部署到生产环境,图片无法正常预览...

本文链接:https://901web.com/post/vue3-vite-dynamic-image-path.html

-- EOF --

Comments

请在后台配置评论类型和相关的值。