I need to load around 1000 static images, .gifs, and videos for an online slideshow presentation. Currently all items are loading at once and viewers need to wait to see the first item. How to load each item after the one before is finished loading?
Vue.js Vuetify.js code:
<v-row v-for="(objkts, index) in group" :key="index">
<v-col v-for="objkt in objkts" :key="objkt.id">
<v-card :key="index" width="100vh">
<v-img
max-width="100vh"
:src="img(objkt)"
></v-img>
</v-card>
</v-col>
</v-row>
Solution:
Using an image list you need to dynamically set the src property on each image only when the previous image is loaded
Steps (5):
<img v-for="(image,index) in group" :key="index" :src="image.src"
<img v-for="(image,index) in group" :key="index" :src="image.src" @load="loadNextimage(index)"/>
loadNextimage(currentIndex){ let nextIndex = currentIndex+1 if( nextIndex < this.group.length){ let img = this.group[nextIndex] img.src = img.asrc delete img.asrc Vue.set(this.group, nextIndex, img) } }
new Vue({
el: '#app',
data(){
return {
group: [
{ id: 1, title: '', asrc: 'https://source.unsplash.com/collection/190727/120x120'},
{ id: 2, title: '', asrc: 'https://source.unsplash.com/collection/8961198/120x120'},
{ id: 3, title: '', asrc: 'https://source.unsplash.com/collection/190723/120x120'},
{ id: 4, title: '', asrc: 'https://source.unsplash.com/collection/KizanWcExgU/120x120'}
]
}
},
mounted(){
this.loadNextimage(-1)
},
methods:{
loadNextimage(currentIndex){
let nextIndex = currentIndex+1
if(nextIndex<this.group.length){
let img = this.group[nextIndex]
img.src = img.asrc
delete img.asrc
Vue.set(this.group,nextIndex,img)
}
}
}
});
img {
height: 120px;
width:120px;
}
img:not([src]){
background: url(https://www.slntechnologies.com/wp-content/uploads/2017/08/ef3-placeholder-image.jpg);
background-size:cover;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>
<div id="app">
<img
v-for="(image,index) in group" :key="index"
:src="image.src"
@load="loadNextimage(index)"
>
</div>
You can use lazy component from vuetify: https://vuetifyjs.com/en/components/lazy/
Wrap your code inside this component and your html will be loaded based on visibility.
This is similar to Alphesh's solution but I think it's a little bit easier to read. The idea is to set up a simple queueing system with three properties:
You'll also have a simple method called queueNextImage which should be called by the mounted hook (to start the first image loading) and then again when an image is finished loading that looks like this:
queueNextImage() {
if(this.loadingImage !== null) {
this.loadedImages.push(this.loadingImage)
}
this.loadingImage = this.imagesToLoad.shift()
}
When you start imagesToLoad will be populated with all the image URLs you'd like to load and loadedImages will be an empty array.
The template will iterate through the loadedImages rendering them in a regular loop and will have a single img element having the src attribute bound to the value of loadingImage and which fires the queueNextImage from the onLoad event of the image.
Full example:
<template>
<div>
<p>
Images to load: <span>{{imagesToLoad.length}}</span>
Loading image: <span>{{loadingImage}}</span>
Images Loaded: <span>{{loadedImages.length}}</span>
</p>
<img v-for="item in loadedImages" v-bind:key="item" v-bind:src="item" />
<img v-on:load="queueNextImage" v-bind:src="loadingImage" />
</div>
</template>
<script>
export default {
mounted: function() {
this.queueNextImage();
},
methods: {
queueNextImage() {
if(this.loadingImage !== null) {
this.loadedImages.push(this.loadingImage)
}
this.loadingImage = this.imagesToLoad.shift()
},
},
data: () => ({
loadedImages: [],
loadingImage: null,
imagesToLoad: Array.from({length:200},(v,k)=>`https://via.placeholder.com/${k+850}`),
}),
};
</script>