I have code that fetches a list of images as an object like
[
{ src: '/path/to/img.jpg', loaded: false },
...
]
and template that then renders them as HTML like:
<div
v-for="image in alltheimages"
:key="image.id" >
<transition name="fade" appear>
<img
:src="image.src"
v-show="image.loaded"
@load="image.loaded = true"
/>
</transition>
</div>
This works well when first loading the page; the images fade in as soon as they're loaded.
However there's a problem when the image is already loaded in cache because then the @load
never fires on the new <img>
element. In these situations I can check the DOM img tag's plete
property, but how can I do that in VueJS?
I've tried v-show="thisplete || image.loaded"
but this
just points to window
. I thought I could use a method call and pass a reference to the element which initiated the call, but I can't find out how to do that either.
I realise I could load all the images separately with new Image()
, bind a listenter to the load
event before I provide src
and from there update the data to say the thing is loaded, but that a whole lotta code and objects - be much nicer to be able to use the DOM elements Vue creates.
I have code that fetches a list of images as an object like
[
{ src: '/path/to/img.jpg', loaded: false },
...
]
and template that then renders them as HTML like:
<div
v-for="image in alltheimages"
:key="image.id" >
<transition name="fade" appear>
<img
:src="image.src"
v-show="image.loaded"
@load="image.loaded = true"
/>
</transition>
</div>
This works well when first loading the page; the images fade in as soon as they're loaded.
However there's a problem when the image is already loaded in cache because then the @load
never fires on the new <img>
element. In these situations I can check the DOM img tag's .plete
property, but how can I do that in VueJS?
I've tried v-show="this.plete || image.loaded"
but this
just points to window
. I thought I could use a method call and pass a reference to the element which initiated the call, but I can't find out how to do that either.
I realise I could load all the images separately with new Image()
, bind a listenter to the load
event before I provide src
and from there update the data to say the thing is loaded, but that a whole lotta code and objects - be much nicer to be able to use the DOM elements Vue creates.
- There's a library for this issue: npmjs./package/vue-images-loaded – ssc-hrep3 Commented Dec 27, 2017 at 0:39
- May not be what you like, but most of my ponents just have a property 'mounted' which I programmatically set from false to true in the mounted lifecycle hook. That would allow you to do something as v-show="mounted && image.loaded". If you care about too much code, write a mixin for it? – David Heremans Commented Dec 27, 2017 at 7:05
4 Answers
Reset to default 7You can do this with a directive.
<div
v-for="image in alltheimages"
:key="image.id" >
<transition name="fade" appear>
<img
:src="image.src"
v-show="image.loaded"
v-loadedifplete="image"
@load="image.loaded = true"
/>
</transition>
</div>
Then in your app.
new Vue({
...
directives: {
loadedifplete: function(el, binding) {
if (el.plete) {
binding.value.loaded = true;
}
}
}
...
});
I didn't have any luck with this method, nor with vue-images-loaded but vue-onload worked like a charm.
In main.js add:
import OnLoad from 'vue-onload'
Vue.use(OnLoad);
and on the images you are loading:
<img
class="gallery__image"
v-onload="[image src]"
/>
then just add whatever css animation you want to to occur in your stylesheet:
/*loaded state*/
.gallery__image {
opacity: 1;
transition: opacity 1s linear;
}
/*unloaded state*/
.gallery__image[data-src]{
opacity: 0;
}
v-cloak might provide the functionality you are looking for https://v2.vuejs/v2/api/#v-cloak
You can bind to the native onLoad
event and call any method in your ponent that you want. demo
<div id="app">
<img v-for="num in [1,2,3,4]"
src="http://lorempixel./400/200"
:onLoad="onLoadHandler()" />
</div>
new Vue({
el: '#app',
methods: {
onLoadHandler: function() {
alert('hi');
}
}
});