Images are a fun part of web development. They look great, and are incredibly important in almost every app or site, but they’re huge and slow. A common technique of late is that of lazy-loading images when they enter the viewport. That saves a lot of time loading your app, and only loads the images you need to see. There are a number of lazy-loading solutions for Vue.js, but my personal favorite at the moment is vue-clazy-load.
It’s basically a dead-simple wrapper with slots that allows you do display a custom image and a custom placeholder. There’s not much else, but it’s incredibly flexible.
Installation
Install vue-clazy-load in your Vue.js project.
# Yarn $ yarn add vue-clazy-load # NPM $ npm install vue-clazy-load --save
main.js (Partial)
import Vue from 'vue'; import App from 'App.vue'; import VueClazyLoad from 'vue-clazy-load'; ... Vue.use(VueClazyLoad); ... new Vue({ el: '#app', render: h => h(App) });
Since vue-clazy-load uses the brand-new IntersectionObserver API, you’ll probably want a polyfill to support it in most browsers. This one works well, but any polyfill that provides the IntersectionObserver API should work.
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>
Usage
Now you can use the <clazy-load><clazy-load> component directly, as shown below.
App.vue
<template> <div id="app"> <!-- The src allows the clazy-load component to know when to display the image. --> <clazy-load src="https://baconmockup.com/400/400/"> <!-- The image slot renders after the image loads. --> <img src="https://baconmockup.com/400/400/" slot="image"> <!-- The placeholder slot displays while the image is loading. --> <div slot="placeholder"> <!-- You can put any component you want in here. --> Loading.... </div> </clazy-load> </div> </template>
This will get you a basic div that starts loading once the element enters the viewport, displays Loading… until the image loads, then displays the image. Nice and simple!
There are, of course a few props you can pass:
- src: String (required) - The src of the image to load.
- tag: String - Which component / element clazy-load will render as. (The default is a boring ‘ol div.)
- element: String - Which element to consider as the viewport. Otherwise the browser viewport is used. (Useful if you have a custom scrolling area.)
- threshold: Array<Number> || Number - How far into the viewing area the clazy-load component needs to be before the load is started. See MDN for more details.
There’s also a single event provided, the load event. Which is, as the name implies, emitted when the image finished loading.
Also of note, you can effectively use any components in the slots, including Vue transition components, as shown below:
<template> <div id="app"> <!-- Boom: Free fade transitions. --> <clazy-load src="https://baconmockup.com/400/400/"> <transition name="fade" slot="image"> <img src="https://baconmockup.com/400/400/"> </transition> <transition name="fade" slot="placeholder"> <div slot="placeholder"> Loading.... </div> </transition> </clazy-load> </div> </template> <style> .fade-enter, .fade-leave-to { opacity: 0; } </style>
I can’t think of a much easier way to handle image preloading. If you can, feel free to send us a message! For now though, I believe vue-clazy-load can handle pretty much any lazy-loading situation. Enjoy!