2

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?

Marcello
  • 173
  • 1
  • 15

2 Answers2

1

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

Adam Orłowski
  • 4,268
  • 24
  • 33
  • It did't work and no other content from json was displayed this time. I think the problem is on ${loadImg(story.cover)}. Tried also loadImg(story.cover) with same result. NOTE i've placed the const and the methods in Stories.vue where I return the json data. – Marcello Feb 17 '19 at 09:50
  • 1
    You probably need to modify the paths in your json file to only include the filename. After all, the context already includes the entire path. Sadly codesandbox does not support require.context, so I can't create an example there. – Sumurai8 Feb 17 '19 at 10:28
  • Oh yeah, I forgot. @Sumurai8 is right. Since you are giving the path in the `require` `images` you only need to put a name of a file in a `.json` file ;-) – Adam Orłowski Feb 17 '19 at 11:33
  • regarding the name of the file, I've done that but it still doesn't work. I am trying to put a codepen up, will post soon. – Marcello Feb 17 '19 at 12:02
  • @AdamOrlov, thanks to your input I have found a very simple solution that worked. I have posted it as an answer. – Marcello Feb 17 '19 at 14:20
  • I'm glad it works ;-) A good practice would be to place this style code in a computed property. Cheers man. – Adam Orłowski Feb 18 '19 at 08:55
1

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!

Marcello
  • 173
  • 1
  • 15