A Vue.js component to lazy load an image automatically when it enters the viewport using lazy Loading at the Browser-Level or as fallback Intersection Observer API.
Plugin is inspired by v-lazy-image.
v-photo is detects support for browser-level lazy loading and uses it as default. If browser-level lazy loading is not supported by browser fallback is Intersection Observer.
More information on: https://web.dev/native-lazy-loading/
npm install v-photo
Warning: You'll need to install the w3c Intersection Observer polyfill in case you're targeting a browser which doesn't support it.
You can register the component globally so it's available in all your apps:
import Vue from "vue";
import vPhoto from 'v-photo';
Vue.use(vPhoto);
Or use it locally in any of your components:
import vPhoto from "v-photo";
export default {
components: {
vPhoto
}
};
You must pass an src
property with the link of the image:
<template>
<v-photo src="http://lorempixel.com/400/200/" />
</template>
That image will be loaded as soon as the image enters the viewport.
You can use the src-placeholder
property to define an image that is shown until the src
image is loaded.
When the src
image is loaded, a is-loaded
class is added, so you can use it to perform animations. For example, a blur effect:
<template>
<v-photo
src="http://lorempixel.com/400/200/"
src-placeholder="http://lorempixel.com/200/200/"
/>
</template>
<style scoped>
.v-photo {
filter: blur(10px);
transition: filter 0.7s;
}
.v-photo.is-loaded {
filter: blur(0);
}
</style>
In case you are using Webpack bundler for images too (just like Vue-cli):
<v-photo
src="http://lorempixel.com/400/200/"
:src-placeholder="require('../assets/img.jpg')"
/>
You could listen to the intersect
and load
events for more complex animations and state handling:
<template>
<v-photo
src="http://lorempixel.com/400/200/"
src-placeholder="http://lorempixel.com/200/200/"
@intersect="..."
@load="..."
/>
</template>
@jmperezperez has written about the progressive loading technique on his blog, in case you want a deeper explanation.
If you want to wrap the img
in a picture
tag, use the prop usePicture
. You can then use slots to add additional elements above the img
element`.
<v-photo
src="http://lorempixel.com/400/200/"
alt="Fallback"
use-picture
>
<source srcset="http://lorempixel.com/1680/1024/" media="(min-width: 1024px)" />
</v-photo>
Renders as:
<picture>
<source srcset="http://lorempixel.com/1680/1024/" media="(min-width: 1024px)" />
<img srcset="http://lorempixel.com/400/200/" alt="Fallback" />
</picture>
Note you can use the picture polyfill.
Fields marked as (*) are required.
Name | Type | Default | Description |
---|---|---|---|
src |
String (*) | - | Image src to lazy load when it intersects with the viewport |
src-placeholder |
String | ' ' | If defined, it will be shown until the src image is loaded. |
alt |
String | ' ' | img alt attribute |
intersection-options |
Object | () => ({}) | The Intersection Observer options object. |
use-picture |
Boolean | false | Wrap the img in a picture tag. |
use-lazy |
Boolean | true | Turn off lazy loading |
Name | Description |
---|---|
intersect |
Triggered when the image intersects the viewport |
load |
Triggered when the image defined in src is loaded |
error |
Triggered when the image defined in src fails to load |