Passing and binding img src from props in Vue.js

Viewed 32106

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.

6 Answers

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

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'/>

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>

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

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.

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>
Related