/v-photo

Vue.js plugin for image and picture elements with support for browser-level lazy loading and intersection observer

Primary LanguageVue

v-photo

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.

Lazy Loading at the Browser-Level

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/

Usage

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.

Progressive Loading

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.

Picture

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.

API

Fields marked as (*) are required.

Props

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

Events

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