Marcello
Marcello

Reputation: 173

How to make Vue display an image from a local path from json file

I'm playing with Vue.js and trying to display a local image from a json file unsuccessfully.

Stories.vue

<template>
  <div class="container col-md-5">
    <div class="Library-title">
      <div class="app-name">Stories List</div>
    </div>
    <story-tyle v-for="story in stories" v-bind:story="story" :key="story.id"></story-tyle>
  </div>
</template>

<script>
import StoryTyle from '@/components/StoryTyle.vue'
import storyData from '@/assets/data/StoriesData.json'

export default {
  name: 'Stories',
  components: {
    StoryTyle
  },
  data () {
    return {
      stories: storyData
    }
  }
}
</script>

StoryTile.vue

<template>
  <div class="story-wrapper col-6">
    <div class="story-cover">
      <div class="story-cover-img" v-bind:style="{ 'background-image': 'url(' + story.cover + ')' }" v-bind:alt="story.title">
        <a v-on:click="nextPath()">
          <div class="story-details cover-select">
            <span v-if="story.frequency" class="story-frequency resize">{{ story.frequency }}</span>
            <div class="story-title resize">{{ story.title }}</div>
            <div class="story-author resize">{{ story.author }}</div>
          </div>
        </a>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  import: require('../assets/js/resize.js'),
  props: ['story'],
  name: 'story-tyle',
  methods: {
    nextPath () {
      if (this.story.frequency) {
        this.$router.push({name: 'Episodes'})
      } else {
        this.$router.push({name: 'Read'})
      }
    }
  }
}
</script>

StoriesData.json

[
  {
    "id": 1,
    "title": "Example of story title",
    "author": "Author Name",
    "cover": "../assets/img/covers/Blue-border-cover.png",
    "frequency": "weekly"
  },
  {
  ...
  }
]

The other data display correctly, but not the cover image. I've looked for different solutions but nothing seems to work. Images loads correctly if I get the data directly in the script of Stories.vue like this:

data () {
    return {
      stories: [
        {
          ...
          cover: require('../assets/img/covers/Blue-border-cover.png')
        },

And this is the relevant folder structure:

src
├─ assets
│   ├─ data
│   │   └─ StoriesData.json
│   └─ img
│       └─ covers
│           └─ Blue-border-cover.png
├─ components
│   └─ EpisodeTyle.vue
└─ views
    └─ Episodes.vue

what am I doing wrong?

Upvotes: 2

Views: 8071

Answers (2)

Marcello
Marcello

Reputation: 173

After the input received in here, I played around with different solution and found a very simple solution that worked.

The problem is that images need to use require. So in StoryTile.vue I replaced:

v-bind:style="{ 'background-image': 'url(' + story.cover + ')' }"

with:

v-bind:style="{ 'background-image': 'url(' + require('../assets/img/covers/' + story.cover) + ')' }"

also in the json file, "cover": "Blue-border-cover.png" and not the entire path which is now expresses in StoryTile.vue.

and this did the trick!

Upvotes: 1

Adam Orłowski
Adam Orłowski

Reputation: 4464

Try to do it this way:

const images = require.context('@/assets/img/covers', false, /\.png$|\.jpg$/)

export default {
  ...
  methods: {
    loadImg(imgPath) {
      return images('./' + imgPath)
    },
    ...
  }

}

In your template:

<div class="story-cover-img"
     :style="`background-image: url(${loadImg(story.cover)})`"
     :alt="story.title"></div>

In .json

[
  {
    "id": 1,
    "title": "Example of story title",
    "author": "Author Name",
    "cover": "Blue-border-cover.png", // only name of a file
    "frequency": "weekly"
  },
  {
  ...
  }
]

Let me know if it worked.


Another idea: .json

[
  {
    "id": 1,
    "title": "Example of story title",
    "author": "Author Name",
    "cover": "url(\'/assets/img/covers/Blue-border-cover.png\')", // set bg url here
    "frequency": "weekly"
  },
  {
  ...
  }
]

And then in your template:

<div class="story-cover-img"
     :style="`background-image: ${story.cover}`"
     :alt="story.title"></div>

Let me know if that worked 😃

Upvotes: 1

Related Questions