51

My Vue component contains some images. I want to do lazy-loading later, so I need to set the src of the images to a small image, first.

<template>
        <div v-for="item in portfolioItems">
            <a href="#{{ item.id }}">
                <img
                    data-original="{{ item.img }}"
                    v-bind:src="/static/img/clear.gif"
                    class="lazy" alt="">
            </a>
        </div>
</template>

Gives me a bunch of errors, like:

[Vue warn]: Invalid expression. Generated function body: /scope.static/scope.img/scope.clear.gif vue.common.js:1014[Vue

[Vue warn]: Error when evaluating expression "/static/img/clear.gif": TypeError: Cannot read property 'call' of undefined (found in component: )

webpack.config.js:
module.exports = {
    // ...
    build: {
        assetsPublicPath: '/',
        assetsSubDirectory: 'static'
    }
}
David
  • 16,246
  • 34
  • 103
  • 162
reggie
  • 3,523
  • 14
  • 62
  • 97

9 Answers9

78

This solution is for Vue-2 users:

  1. In vue-2 if you don't like to keep your files in static folder (relevant info), or
  2. In vue-2 & vue-cli-3 if you don't like to keep your files in public folder (static folder is renamed to public):

The simple solution is :)

<img src="@/assets/img/clear.gif" /> // just do this:
<img :src="require(`@/assets/img/clear.gif`)" // or do this:
<img :src="require(`@/assets/img/${imgURL}`)" // if pulling from: data() {return {imgURL: 'clear.gif'}}

If you like to keep your static images in static/assets/img or public/assets/img folder, then just do:

<img src="./assets/img/clear.gif" />
<img src="/assets/img/clear.gif" /> // in some case without dot ./
Syed
  • 15,657
  • 13
  • 120
  • 154
  • 1
    using vue-cli-3, this answer finally did it for me loading in a path string dynamically. – Dan Oswalt Sep 21 '18 at 02:41
  • 3
    worked for me. My file structure is in /assets/img/clear.gif. Thank you for a lot of options to choose from. Finally, one worked for me. – Vince Banzon Dec 11 '18 at 06:43
  • @VinceBanzon glad that helped you, don't forget to up vote ;) – Syed Dec 11 '18 at 13:48
  • 1
    This still works with VueCLI 4.4. Thanks kind sir, you just got upvoted!! ;) – Rodrigo May 27 '20 at 17:34
  • I put '@' inside of the variable. Your solution you put '@' inside the tag and the variable you put only the name of file, not path. it was great! Thank you! – LUISAO Jun 30 '21 at 03:07
51

If you want to bind a string to the src attribute, you should wrap it on single quotes:

<img v-bind:src="'/static/img/clear.gif'">
<!-- or shorthand -->
<img :src="'/static/img/clear.gif'">

IMO you do not need to bind a string, you could use the simple way:

<img src="/static/img/clear.gif">

Check an example about the image preload here: http://codepen.io/pespantelis/pen/RWVZxL

Pantelis Peslis
  • 14,930
  • 5
  • 44
  • 45
  • Your example is broken and I'm not sure if actually works as other answers clearly point out to use require('@/assets/...') for the :src prop. – ShadowGames Mar 18 '23 at 15:04
22

This is how i solve it.:

      items: [
        { title: 'Dashboard', icon: require('@/assets/icons/sidebar/dashboard.svg') },
        { title: 'Projects',  icon: require('@/assets/icons/sidebar/projects.svg') },
        { title: 'Clients', icon: require('@/assets/icons/sidebar/clients.svg') },
      ],

And on the template part:

<img :src="item.icon" />

See it in action here

Roland
  • 24,554
  • 4
  • 99
  • 97
10

@Pantelis answer somehow steered me to a solution for a similar misunderstanding. A message board project I'm working on needs to show an optional image. I was having fits trying to get the src=imagefile to concatenate a fixed path and variable filename string until I saw the quirky use of "''" quotes :-)

<template id="symp-tmpl">
  <div>
    <div v-for="item in items" style="clear: both;">
      <div v-if="(item.imagefile !== '[none]')">
        <img v-bind:src="'/storage/userimages/' + item.imagefile">
      </div>
      sub: <span>@{{ item.subject }}</span>
      <span v-if="(login == item.author)">[edit]</span>
      <br>@{{ item.author }}
      <br>msg: <span>@{{ item.message }}</span>
    </div>
  </div>
</template>
rickatech
  • 551
  • 4
  • 10
7

declare new variable that the value contain the path of image

const imgLink = require('../../assets/your-image.png')

then call the variable

export default {
    name: 'onepage',
    data(){
        return{
            img: imgLink,
        }
    }
}

bind that on html, this the example:

<a href="#"><img v-bind:src="img" alt="" class="logo"></a>

hope it will help

Zoe
  • 27,060
  • 21
  • 118
  • 148
Cevin Ways
  • 984
  • 11
  • 13
2

You need use just simple code <img alt="img" src="../assets/index.png" />

Do not forgot atribut alt in balise img

Lamri Djamal
  • 236
  • 1
  • 10
2

I had a similar issue with Vue where I tried to display several images by importing data from a configuration json file and then iterating over the data using v-for.

Even when I put require('../../assets/' + filename) right in the json, the images would never show. I eventually realized that Vue was interpreting my data value as a string, rather than a function. Good thing that javascript supports functions as a return type. So I made this function:

  getImagePath(filename: string) {
    return require('../../assets/' + filename);
  }

I then just called that function from my v-for loop simply passing in the filenames from my config:

<v-list-item :key="place.id" v-for="place in placesOfPower">
  <v-list-item-content class="justify-end">
    <v-img :src="getImagePath(place.image)"
           position="top center"
           height="90"
           width="30vw"/>
  </v-list-item-content>
<v-list-item-content>
0

I found this thread on my search for a solution to show an image when it exists. I want to show a list of database entries that contain a type property. Each type should have a fitting png file in my vue assets folder. The whole list would break if a new type would be added without adding the image beforehand.

I found "Catch an error on requiring module in node.js" on stack overflow. The answer by Peter Lyons led me to my solution:

<template>
  <v-data-table :items="items">
    <template v-slot:item.type="{ item }">
      <v-img
        v-if="typeImageSource(item.type)"
        :src="typeImageSource(item.type)"
      />
      <template v-else>
        {{ item.type }}
      </template>
    </template>
  </v-data-table>
</template>

<script>
export default {
  data () {
    return {
      // In reality this gets filled from a db:
      items: [
        { id: 1, type: 'abc' },
        { id: 2, type: 'abcd' },
        { id: 3, type: 'efg' },
      ]
    }
  },
  methods: {
    typeImageSource: function (type) {
      let src = ''
      try {
        src = require(`@/assets/types/${('' + type).toLowerCase()}.png`)
      } catch (error) {
        console.warn(`Image for type ${type} could not be found! Please add "${('' + type).toLowerCase()}.png" to the folder "@/assets/types/".\n\n`, error)
        return null
      }
      return src
    },
  },
}
</script>
sebix
  • 39
  • 7
0

If you are using nuxt use <img :src="'_nuxt/path_to_your_local_image'" />

if you are using vue first use static src import : <img src="path_to_your_local_image" />

then inspect image element to see what src is rendered to the browser then replace it with a dynamic src

fafa.mnzm
  • 561
  • 7
  • 17