12

I am trying to display an image with the img tag by using a path from props for the src attribute.

I've tried changing the path with @, using the whole path with src, adding ../assets/ in the component and only passing the file name (orange.png) as props. I always get the default broken image displayed. When inspecting in the browser, the path seems fine. When I display the image directly, I can see that the path is resolved to some different path <img data-v-1212d7a4="" src="/img/orange.7b71a54c.png">.


Edit: Additionally I tried this post Can't dynamically pass relative src path for imgs in Vue.js + webpack , where using <img :src="require(picture_src)" /> is given as an answer. This leads to an error: Error in render: "Error: Cannot find module '../assets/orange.png'"

(Edit2: This answer in the end worked for me in the end as described in my answer post.)
The same error occurs with the similar webpack method using let images = require.context('../assets/', false, /\.png$/) in my script part, as the answer on this post Can't dynamically pass relative src path for imgs in Vue.js + webpack .


I am new to Vue.js, so I don't exactly know what is happening or how to search for this or it might not have anything to do with what I'm originally trying.

I am able to display my image when I pass the path directly, like this

<img src="../assets/orange.png"/>

Now I'd actually like to pass it to my component in the props and then, inside the component, display it reading the path from props.

Component

<template>
  <div>
    <img :src=picture_src />
    <div class="pic_sub">{{pic_desc}}</div>
  </div>
</template>
<script>
export default {
  name: 'PictureCard',
  props: {
    picture_src: String,
    pic_desc: String
  }
}
</script>

Using the component:

<template>
  <div>
    <PictureCard pic_desc='some description text' picture_src='../assets/orange.png' />
  </div>
</template>

<script>
import PictureCard from './components/PictureCard.vue'
export default {
  name: 'app',
  components: {
    PictureCard
  }
}
</script>

If it is possible, I'd love to display my from a path that is passed through the component's props.

Otherwise I'd love to know some other solutions, work-arounds or knowledge on best practices in this case.

turninglights
  • 301
  • 1
  • 2
  • 12
  • How about passing the image directly, instead of source string? For example import the image in your Main Component and pass it in PicutureCard? – keysl Jun 17 '19 at 04:51
  • This question comes up a lot. The easy fix is to use `:src="require(picture_src)"` – Phil Jun 17 '19 at 05:09
  • Possible duplicate of [Vue.js - Trying to bind dynamic images... what should I do?](https://stackoverflow.com/questions/49901191/vue-js-trying-to-bind-dynamic-images-what-should-i-do) and [Vue.js dynamic images not working](https://stackoverflow.com/questions/40491506/vue-js-dynamic-images-not-working) – Phil Jun 17 '19 at 05:11
  • Prob the best practice here is to create new Image with js and use url from props – Sergey Shapirenko Jun 17 '19 at 08:34
  • Thank you for the feedback. When I try to use `:src="require(picture_src)"` I get an error and the whole component doesn't render anymore. `Error in render: "Error: Cannot find module '../assets/orange.png'"` – turninglights Jun 18 '19 at 02:40
  • What do you mean by importing the image or creating new image with js? – turninglights Jun 18 '19 at 02:44
  • Your path is probably incorrect (relative to the `PictureCard` component). Try binding `@/assets/orange.png`. Another problem might be that you do not have the file-loader or its not configured for `.png` images though this should not be the case for a project built using Vue CLI v3. – Phil Jun 18 '19 at 03:18
  • I think the path should be correct since I use the same path that displays the picture when I use it directly in the src attribute. (Or that would be wrong?) I'm not sure how/where to check configurations for the file-loader. Thank you for your answers. It helped me research in the right direction and posted what worked for me and why below. – turninglights Jun 18 '19 at 03:51
  • In short, We can alter transformAssetUrls option of Vue loader to archive this. Can refer to my answer to another similar question: https://stackoverflow.com/a/72877371/1280871 – James Chen Jul 06 '22 at 02:36

6 Answers6

40

This worked for me

<img :src="require(`@/assets/img/${filename}`)">

where filename is passed in as a String prop e.g. "myImage.png".

Make sure you use the path specific to your project.

Source: https://github.com/vuejs-templates/webpack/issues/450

Note: @ is a webpack alias for /src that is set by default in Vue projects

M3RS
  • 6,720
  • 6
  • 37
  • 47
7

Newer solution:

The 'require()'-method does not work when using Vite.

I got this error: ReferenceError: require is not defined.


This is how I solved it without 'require()' and with composition API:

From parent component:

<ChildComponent icon-filename="icon.svg" />

ChildComponent:

<template>
  <div>
    <img :src="getImageUrl()">
  </div>
</template>

<script setup lang="ts">
import {defineProps} from "vue";

const props = defineProps({
  iconFilename: String
})

function getImageUrl() {
  // This path must be correct for your file
  return new URL(`../assets/icons/${props.iconFilename}`, import.meta.url)
}

</script>
Otziii
  • 2,304
  • 1
  • 25
  • 34
5

After some research, I understand that my problem has to do with webpack and resolving filepaths. I used a modified version from this answer:
Vue.js dynamic images not working
and this answer:
Can't dynamically pass relative src path for imgs in Vue.js + webpack
Since the link in the second answer was dead, here's an active link to require.context documentation: https://webpack.js.org/guides/dependency-management/#requirecontext

My mistake when trying the second link's answer was that I returned only orange.png as the path, while I needed to add ./ at the beginning.

My working picture component now looks like this.

<template>
  <div>
    <img :src="resolve_img_url(picture_src)" />
    <div class="pic_sub">{{pic_desc}}</div>
  </div>
</template>
<script>
export default {
  name: 'PictureCard',
  props: {
    picture_src: String,
    pic_desc: String
  },
  methods: {
    resolve_img_url: function (path) {
      let images = require.context('../assets/', false, /\.png$|\.jpg$/)
      return images("./"+path)
    }
  }
}
</script>

I edited the regular expression to match .png and .jpg file endings. Therefore passing the prop looks like this now

<PictureCard  picture_src='orange.png' pic_desc='some picture description'/>
turninglights
  • 301
  • 1
  • 2
  • 12
4

This works for me:

This is how i use my Componenent.

<image-element 
  :imageSource="require('@/assets/images/logo.svg')">
</image-element>

My Image Component:

<template>
  <div>
   ...
     <img v-bind:src=imageSource />
   ...
  </div>   
</template>

<script lang="ts">
 import Vue from 'vue'
 import { Component, Prop } from 'nuxt-property-decorator'

 @Component({
   components: {
    .....
   }
 })
 export default class extends Vue {
  ...
  @Prop({ default: '' }) imageSource!: String
  ...
 }
</script>
Dennis Schaffer
  • 556
  • 7
  • 17
0

this is my favorite super simple way to do it. It can easily be reused in any file in any folder in my project. Just pass the actual path as a string from the perspective of the parent:

//some file
    <ParentA>
      <ImageComponent 
         myImagePath="../../../../../myCat.png"
      />
    </ParentA>

//some other file in a different folder in my project
    <ParentB>
      <ImageComponent 
         myImagePath="../../myCat.png"
      />
    </ParentB>


//child component file
<template functional>
   <div>
      <img :src="props.myImagePath">
   </div>
</template
Jar
  • 1,766
  • 1
  • 21
  • 27
0

Thats all not working for me :D

The template File is wrong! you need to add ":" before you set your prop.

thats how i should use the PictureCard

<PictureCard  :picture_src="require('orange.png')"
 pic_desc='some picture description'/>

and thats how my PictureCard should look like:

<template>
  <div>
    <img v-bind:src="picture_src" />
  </div>
</template>

export default class PictureCard extends Vue {

@Prop({ default: require("@/assets/orange.svg") }) img!: string
 }

so in case no prop is setted, so i added a default prop too. and yes i only used the image.

Dennis Schaffer
  • 556
  • 7
  • 17