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

Jer*_*ung 5 css data-binding vue.js vue-props vue-composition-api

客观的

我想将图像的路径作为道具传递给组件。我希望组件使用 prop 来动态生成背景图像。

我的所有图像都位于 Vue src 文件夹中的 asset 文件夹中。该路径看起来像“@/assets/images/subject/computers.jpeg”

问题

没有背景图像出现

这是页面上呈现的内容:

在此输入图像描述

然而,什么也没有出现

奇怪的行为

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

这是我的 CSS 中的样子

在此输入图像描述

但问题是它不是动态渲染的 CSS。

我进一步检查了该元件并发现了一些奇怪的行为。如您所见,内联样式将图像路径读取为“@/assets/images/subject/computers.jpeg”(下图中的 element.style)。

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

在此输入图像描述

问题

我想我的问题是双重的:

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

解决方案

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

我能够使用计算属性来解决这个问题,如下所示:

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

由于 VueLoader(Vue 中的默认设置)解析路径的方式,我无法将“@”路径存储在 prop 本身中。相反,该 prop 只是图像/文件名(例如“computers.jpeg”),并且使用 require() 的计算属性处理解析图像的前置路径。

之后,我将计算属性添加到绑定的内联样式中,如下所示:

<div class="subject-wrapper" v-bind:style="{ backgroundImage: `url('${imgSrc}')` }">
Run Code Online (Sandbox Code Playgroud)

瞧!它终于起作用了。

总长DR

传递图像/文件名作为 prop,并在计算属性中使用 require() 在路径前面添加路径。

干杯

Ber*_*org 2

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

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

来源

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

resolve: {
     alias: {
          "@": fileURLToPath(new URL("./src", import.meta.url)),
          ...
     }
}
Run Code Online (Sandbox Code Playgroud)

当资源 URL 位于以下 html 标签中时,VueLoader 会对其进行转换:videosourceimgimage(svgs) 和use(svgs)。此外,如果您将 VueLoader 配置为使用css-loader.

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

来源

当您 v 绑定样式属性时,不会发生此资源 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>
Run Code Online (Sandbox Code Playgroud)

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

编辑:您还可以使用require带有if-elseternaryswitch语句的方法来获取图像的相对路径(如果可以设置为背景的图像数量不是太多 - 否则使用文件public夹)。

有了Vite你就可以使用vite-plugin-require插件来进行require()工作了。

  • 保持动态资源 URL 跨环境以及在服务器文件夹内提供的应用程序中工作的正确方法是使用“require()”,它与相对路径一起使用。示例:`const bgSrc =计算(()=&gt;条件?require('pathA'):require('pathB'))`。使用“location.origin”会破坏很多用例。 (2认同)