1. 引言

在使用Vite开发项目时,你可能会遇到这样的情况:**在开发环境中,你可以正常引入图片,但是在打包后的生产环境中,图片却无法正确显示。**这是因为Vite默认会在打包后的资源文件名中添加哈希值,但是直接通过:src="imgSrc"方式引入图片时,不会在打包时解析路径。

2. Vite 路径自动解析

Vite在打包时可以自动转换图片路径为hash化的路径,以确保缓存一致性和资源文件的唯一性。以下是几种情况下Vite可以自动转换图片路径的情况

2.1 Vite 路径别名的配置

Vite允许开发者通过配置路径别名来简化模块引用时的路径书写,常见的别名符号包括@#$等。在vite.config.js中通过resolve.alias配置项设置别名。

以下是在Vite中配置路径别名的示例:

import path from "path";

exportdefaultdefineConfig({
  resolve: {
    alias: [
      {
        find: "@",
        replacement: path.resolve("./src"), //将'@'映射到'/src'目录
      },
    ],
  },
});

在示例中,@是我们定义的别名,它映射到了/src这个实际的文件路径上。这样,在项目中引用模块时,使用这些别名来代替实际的文件路径,使得代码更加简洁清晰。

注意:当使用文件系统路径的别名时,请始终使用绝对路径。相对路径的别名值会原封不动地被使用,因此无法被正常解析。

2.2 Vite 路径解析并自动转换的情况

2.2.1 CSS 中的引用

background-image: url('../../assets/image/apple.png'); /*使用相对路径引用图片*/
background-image: url('@/assets/image/logo.png'); /*使用路径别名引用图片*/

可以使用相对路径路径别名CSS中引用图片,Vite会自动转换图片路径为hash化的路径。

注意:避免使用绝对路径动态路径,防止图片无法加载。

2.2.2 HTML中的引用

<img src="../../assets/image/apple.png">
<img src="@/assets/image/logo.png">

<img>标签的src属性的值是一个静态路径,可以使用相对路径或路径别名引用图片,Vite会自动转换图片路径为hash化的路径。

2.2.3 模块引用

import apple from'../../assets/image/apple.png';  //使用相对路径引用图片
import logo from'@/assets/image/logo.png';  //使用别名@/assets引用图片

这里导入的applelogo的内容是一个路径,并且Vite会自动将图片路径转换为hash化的路径,以便浏览器能够正确加载它们。

3.静态文件的动态引入

对于在Vite中动态引用静态文件,有几种常见的方法,包括使用public目录、import语句以及newURL构造函数。下面我将逐一介绍这些方法:

3.1使用 public 目录

public中的文件,是不会经过编译的,打包后会生成dist文件夹,public中的文件只是复制一遍。因此,如果你的资源文件不会改变,可以采取这种方案。

  • 将静态文件放置在项目的public目录中。
  • 在代码中直接引用静态文件的路径,路径从项目根目录开始。
  • 这种方法适用于不需要进行额外处理的静态文件,例如图片、字体等。

3.1.2示例:动态切换 public 目录下的文件

<template>
  <div>
    <img :src="imgSrc" :alt="imgName">
  </div>
</template>

<script setup lang='ts'>
import { computed, ref } from 'vue';

const imgName = ref('jack');
const imgSrc = computed(() => `/avatar/${imgName.value}.png`)
</script>

Vite在构建时会将public目录下的静态文件直接复制到输出目录,因此最终渲染出的页面能够正确加载图片。

优点:使用public目录的好处是可以简化资源引用路径,使得前端代码更加清晰和易于维护。
缺点:需要注意的是,这种方式不会对资源进行任何的转换或优化,因此对于大型项目或需要进行缩放或压缩的图片,可能需要额外的处理手段。

3.2 使用 import 语句

-在代码中使用ES模块的import语句来引用静态文件。
-Vite会自动处理这些静态文件,并将其转换为正确的URL路径。
-这种方法适用于需要在代码中动态引用的静态文件,例如图片、样式表等。

对于import语句,Vite可以正确地解析变量作为路径,因为它会动态地在运行时加载模块。

3.2.1 示例:动态绑定导入的图片

<template>
  <div>
    <img :src="logo" alt="logo">
  </div>
</template>

<script setup lang='ts'>
import logo from '@/assets/logo.png'; //可以使用相对路径,也可以使用路径别名
</script>

使用场景:如果引用的文件数量不多,可以采用这个方法。

3.3 使用 newURL 构造函数

-使用JavaScriptnewURL构造函数来动态生成静态文件的URL
-这种方法可以根据当前页面的URL动态生成静态文件的完整路径。
-适用于需要根据运行时条件动态引用静态文件的情况。

注意:当Vite在编译阶段遇到newURL()构造函数时,它需要在静态分析阶段准确地解析路径。如果newURL()的第一个参数是一个变量,在编译阶段无法确定路径,就会导致路径解析不准确,从而可能导致开发环境显示正确,但在打包后文件路径无法解析,导致图片等资源无法显示和使用的问题。

3.3.1 示例1:在统一路径下的文件切换

<template>
  <div>
    <img :src="currentImageUrl" alt="CurrentImage">
    <div>
      <button @click="switchImage('image1')">Image1</button>
      <button @click="switchImage('image2')">Image2</button>
      <button @click="switchImage('image3')">Image3</button>
    </div>
  </div>
</template>


<script setup lang='ts'>
import { ref } from 'vue';

const currentImageUrl = ref('');
const switchImage = (imageName: string) => {
  currentImageUrl.value = new URL(`../../assets/images/${imageName}.jpg`, import.meta.url).href;
};

switchImage('image1');
</script>

在这个示例中,我们假设在assets/images目录下存放了image1.jpgimage2.jpgimage3.jpg三张图片。然后我们定义了一个switchImage方法,该方法接受图片文件名作为参数。在方法内部,我们使用newURL构造函数来构建图片文件的完整URL,然后将构建的图片URL赋值给currentImage属性,以便在页面上显示当前图片。当点击按钮时,会调用switchImage方法,并根据传入的图片文件名来切换图片。

3.3.2 示例2:展示某统一路径下的所有文件

使用场景:预加载所有图片,从而提高用户体验。这种方法特别适用于需要在页面中展示大量图片的情况,比如图片画廊、相册等。

<template>
  <div>
    <img v-for="image in images" :src="image" :key="image">
  </div>
</template>

<script setup lang='ts'>
import { ref } from 'vue';

const images = ref<string[]>([]);

const importAllImages = () => {
  const imagePaths = Object.keys(import.meta.glob("../../assets/image/bg/*.{png,jpg,gif,svg}")).map((path) => {
    const imageName = path.replace('../../assets/image/bg/', '');
    return new URL(`../../assets/image/bg/${imageName}`, import.meta.url).href;
  });
  images.value = imagePaths;
}

importAllImages();
</script>

首先,通过import.meta.glob()方法批量获取指定目录下的所有图片文件的路径。import.meta.glob()返回一个对象,其键是匹配到的文件路径,值是一个函数,可以立即执行以获取匹配文件的内容。
我们使用Object.keys()获取所有匹配到的文件路径,并通过map()方法遍历这些路径。
map()方法中,我们对每个文件路径执行了replace()方法,将路径中的目录部分替换为空字符串,得到了图片文件的名称。
接着,我们使用newURL()构造函数来构建每个图片文件的完整路径,使用基础路径和图片文件名作为参数。最后,将构建的路径添加到images数组中。

4. 参考

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐