前言
在 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 中,它会在以下几种情况下帮你自动转换路径:
- css 中的静态路径
.container {
background-image: url(....);
}
- Image 中的
src
属性(静态路径) - 动态 import 语句
- 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 会给图片资源添加上指纹,并不需要在代码中显式引入带有文件指纹的图片资源。