[Vuejs]-Dynamic rendering of images with v-for?

-1👍

I don’t think I was clear enough with my comments, so I’ll explain what I meant with an example; you should be able to apply this to your use case with minimal effort. My src file structure and a screenshot of the result are also at the bottom of this answer.


The template I’ve made is basically the same as yours (without the extra divs with classes):

<template>
  <div>
    <div v-for="image in images" :key="image">
      <img :src="selectImage(image)" :alt="image" />
    </div>
  </div>
</template>

Here’s my script. I’ll go through it all below:

<script>
  export default {
    name: 'app',
    computed: {
      images: function() {
        const x = require.context('@/assets/card-images/', true, /\.png$/)
        return this.importAll(x)
      }
    },
    methods: {
      importAll(r) {
        return r.keys().map(x =>
          x.substring(2, x.length) // remove "./" from file names
        )
      },
      selectImage(image) {
        return require('@/assets/card-images/' + image)
      }
    }
  }
</script>

computed

The computed section is where you define your dynamically generated or computed values. Since you want your images to be dynamically generated, I’ve made images a computed function (can probably just be a value, you can play around with that).

All that images does is it uses require.context to get a list of all of the .png images in my @/assets/card-images/ folder, and trims the first couple of characters from them.

methods

importAll just retrieves and trims the image names. I’ve done this because otherwise, it’ll think the images are at @/assets/card-images/./xxxxx.png – there’s probably a better way of doing this but it works well enough.

selectImage gets an image from the file name you pass in (if it exists). If the image name doesn’t exist, this will break but that shouldn’t happen with how this is implemented.


Note: You can technically shorten the v-for loop by putting it directly on the img tag if you really want to, though I’d argue this is less readable:

<template>
  <div>
    <img v-for="image in images"
         :key="image"
         :src="selectImage(image)"
         :alt="image" />
  </div>
</template>

Here is my src folder structure. It doesn’t matter what the images are called, as long as they have the same extension as you’re using in your script tag:

folder structure

Here is what the code prints out (all of the images are just copies of the Vue logo):

output


EDIT

If you want to keep your initial images array, you can move the computed stuff into the lifecycle method mounted or created (depending on your use-case). Read more about lifecycle methods here or here. Here’s what my component would look like with the calculations in mounted:

<template>
  <div>
    <div v-for="image in images" :key="image">
      <img :src="selectImage(image)" :alt="image" />
    </div>
  </div>
</template>

<script>
  export default {
    name: 'app',
    data() {
      return {
        images: []
      }
    },
    mounted() {
      const x = require.context('@/assets/card-images/', true, /\.png$/)
      this.images = this.importAll(x)
    },
    methods: {
      importAll(r) {
        return r.keys().map(x =>
          x.substring(2, x.length) // remove "./" from file names
        )
      },
      selectImage(image) {
        return require('@/assets/card-images/' + image)
      }
    }
  }
</script>

-1👍

Use a requireAll method to get an array, and your count. Or a custom loader.

How to load all files in a directory using webpack without require statements

node.js require all files in a folder?

Leave a comment