如何使用props在Vue中为组件创建动态背景图像?

5

目标

我想将一张图片的路径作为prop传递给一个组件。我希望这个组件使用这个prop来动态生成背景图片。

我的所有图片都在Vue src文件夹中的assets文件夹中。 路径看起来像这样'@/assets/images/subject/computers.jpeg'

问题

没有出现背景图片

这是页面上呈现的内容:

enter image description here

然而,什么也没有显示出来

奇怪的行为

由于某种原因,在CSS中添加完全相同的路径名'@/assets/images/subject/computers.jpeg'有效(将其添加到<style>标签中)。 如果它是v-bind内联样式,则不起作用。

这是我的CSS中的样子

enter image description here

然而,这个问题是它不是动态呈现的CSS。

我进一步检查了元素并注意到一些奇怪的行为。正如您所看到的,内联样式将图像路径读取为'@/assets/images/subject/computers.jpeg'(下面图像中的element.style)。

而在CSS中添加路径,则将'@/assets/images/subject/computers.jpeg'更改为'http://localhost:8080/img/computers.7f3748eb.jpeg',然后正确呈现背景图像。

enter image description here

问题

我想我的问题有两个方面:

  1. 如何使用props在Vue中动态渲染背景图片?或者有更好的方法吗?
  2. 为什么绑定内联样式不能解析路径(仍然使用“@”),而直接添加到<script>标签中可以解析路径?

解决方案

好的,非常感谢taoBernard Borg帮助我理解这个问题。

我能够使用计算属性来解决这个问题,就像这样:

const imgSrc = computed(() => require(`@/assets/images/subject/${props.subject.image}`))

由于Vue默认使用的VueLoader解析路径的方式,我无法将“@”路径存储在prop本身中。相反,prop只是图像/文件名称(例如“computers.jpeg”),并且使用require()处理计算属性以解析前置路径到图像。
随后,我将计算属性添加到我的绑定内联样式中,如下所示:
<div class="subject-wrapper" v-bind:style="{ backgroundImage: `url('${imgSrc}')` }">

哇!它终于可以工作了。

简短概述

只需将图像/文件名称作为属性传递,并在计算属性中使用require()添加路径前缀即可。

干杯!


1
在幕后,Vue 使用 VueLoader 解析环境相关的正确资源路径(在开发时有不同的路径,生产构建时也有不同的路径)。请阅读资产 URL 处理,特别是 转换规则 - tao
1个回答

2

在使用Webpack(Vue-cli)时,@符号是src文件夹的别名。

如果URL以@开头,则也会被解释为模块请求。如果您的webpack配置具有@的别名,默认情况下指向vue-cli创建的任何项目中的/src,这将非常有用。

来源

如果您正在使用Vite,则可能在vite.config.js中有以下内容;

resolve: {
     alias: {
          "@": fileURLToPath(new URL("./src", import.meta.url)),
          ...
     }
}

VueLoader会在以下HTML标签中转换资源URL:videosourceimgimage(SVG)和use(SVG)。此外,如果您已经配置了VueLoader使用css-loader,它还会在style标签中转换资源URL。

所有编译后的CSS都会被css-loader处理,它解析url()并将其解析为模块请求。

当您v-bind样式属性时,不会发生此资源URL转换。

您可以使用此机制将转换后的路径传递给另一个组件(例如来自库的组件)。尽管如此,您仍需要像@tao提到的那样声明每个单独的路径。

这里相关的要点是,VueLoader必须在编译应用程序时读取所有可能的路径并解析它们。

<script setup lang="ts">
import BackgroundImageViewer from './components/BackgroundImageViewer.vue'
import { ref, onMounted } from "vue";

const hiddenImage = ref<HTMLImageElement>();
const thePath = ref();

onMounted(() => {
    if (hiddenImage.value) {
        thePath.value = hiddenImage.value.src;
        hiddenImage.value.src = "";
    }
});
</script>

<template>
    <img src="@/assets/vue.svg" ref="hiddenImage" hidden />
    <BackgroundImageViewer :path="thePath"/>
</template>

正如 @tao 也提到的,如果不同图像的数量过多,您可以选择将图像放置在项目的 public 文件夹中。

编辑:您还可以使用 require 方法结合 if-else 树、ternaryswitch 语句来获取图像的相对路径(如果可设置为背景的图像数量不太多的话 - 否则请使用 public 文件夹)。

使用 Vite,您可以使用 vite-plugin-require 插件使 require() 函数正常工作。


2
保持动态资产URL在各种环境下正常工作的正确方法,以及在服务器文件夹中提供的应用程序内使用是使用require()与相对路径一起运行。例如:const bgSrc = computed(() => condition ? require('pathA') : require('pathB')) 。使用“location.origin”会破坏很多使用情况。 - tao
好的 - 你指的是哪个条件? - Bernard Borg
任何情况下,请阅读您正在回答的问题的标题。 - tao
这是无关的。使用 switch。这里相关的点是VueLoader在编译应用程序时必须读取所有可能的路径并解决它们。我猜想一个人想让他们的应用程序在部署时工作。仅在提供服务时使其工作几乎没有意义。 - tao
@tao 如果有任何信息不正确,请更正我的更新答案 - 我无法弄清楚如何使 require 工作。 - Bernard Borg
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接