Skip to content

Vue.js 中的静态资源动态访问

Published:

前言

在 Vue.js 项目中,动态加载图片是一个常见的需求。比如说,我们可能需要根据用户选择的不同选项来显示不同的图片。这个需求听起来简单,但在实际操作中可能会遇到一些困惑。这主要是因为对工程化的理解不够清晰。比如,你可能会在 assets/images 文件夹下存放了很多图片,而在代码中如何动态切换这些图片呢?

这些图片通常都放在工程目录中的 assets/images 文件夹下。

而在我们的源代码里边,当我们的选项发生改变时,会运行一个函数,这个函数会拿到你目前选择的结果,这是一个非常简单的需求。那么如何来实现动态切换呢?

基本思路

我们可以通过绑定 styles 来动态设置背景图片,并在选项发生变化时更新图片路径。例如:

<template>
  <div class="container" :style="{ backgroundImage: `url(${path})` }">
    <TypeSelector @selector="onSelector" />
  </div>
</template>

<script setup>
import { ref } from "vue";

const path = ref("/assets/images/Winter.jpg");

function onSelector(value) {
  path.value = `/assets/images/${value}.jpg`;
}
</script>

可以看到,这里明明绑定了 url 地址,但是为什么会显示不出来呢?

如果我们在 css 中使用静态地址,可以看到图片的 url 地址变成上图正常的情况。

原因分析

为什么我们在代码中设置的 url 地址显示不出来呢?这是因为在打包后的代码中,图片路径需要带有文件指纹(也就是类似 Winter.xxxxx.jpg 的形式)。在 css 中使用静态路径是有效的,因为 Vite.js 会在打包时自动处理这些路径。

在 Vite.js 中,它会在以下几种情况下帮你自动转换路径:

  1. css 中的静态路径
.container {
  background-image: url(....);
}
  1. Image 中的 src 属性(静态路径)
  2. 动态 import 语句
  3. URL 构造函数

所以,我们在代码中使用相对路径并不是打包后的路径,也无法被 Vite.js 识别。

解决方案

更换图片存放的路径

最简单粗暴的做法就是将所有图片放在 public/ 下而不是在 assets/ 下,那么在代码中直接使用绝对路径引用图片资源后,图片是可以访问的。

这是因为代码中的绝对路径与打包后的图片路径是一样的,且 Vite.js 不会对这些存放在 public/ 文件夹下的图片进行处理(如添加文件指纹)。

const path = ref("/assets/images/Winter.jpg");

function onSelector(value) {
  path.value = `/assets/images/${value}.jpg`;
}

这种方法虽然简单,但会失去文件指纹带来的缓存优化好处。如果你的图片不常变化,这种方法是可以接受的。

使用 import

你还可以使用动态 import 来加载图片。这种方法让 Vite.js 在打包时自动处理图片路径,生成正确的文件指纹。示例代码如下:

function onSelector(value) {
  import(`./assets/images/${value}.jpg`).then(res => {
    path.value = res.default;
  });
}

它为什么可以做到呢?这还是得益于 Vite.js 的自动分析,如果 Vite.js 发现 import 语句中是字符串,其中一部分是动态的,其他部分是静态的,它会把所有后缀名为 jpg 的图片全部生成到打包结果。于是我们看到所有的图片资源和相关的 JavaScript 文件都在 dist 里。

相关的 JavaScript 文件则是把图片资源导入再默认导出,相当于一个 alias

URL 构造函数

还有一种办法是使用 URL 构造函数,它的作用是产生一个 URL 地址对象,第一个参数是相对路径,第二个参数是 base,而这个参数的值则由 VIte.js 来提供。

function onSelector(value) {
  path.value = new URL(`./assets/images/${value}.jpg`, import.meta.url);
}

这也得益于 Vite.js 的自动分析,转化 URL 与 import 一样,必须要保证第一个参数的一部分是静态的,一部分是动态的。而且在打包的过程中 Vite.js 会给图片资源添加上指纹,并不需要在代码中显式引入带有文件指纹的图片资源。