1 | # Vue-Lazyload
|
2 |
|
3 | [![Build Status](https://img.shields.io/circleci/project/hilongjw/vue-lazyload/master.svg?style=flat-square)](https://circleci.com/gh/hilongjw/vue-lazyload)
|
4 | [![npm version](https://img.shields.io/npm/v/vue-lazyload.svg?style=flat-square)](http://badge.fury.io/js/vue-lazyload)
|
5 | [![npm downloads](https://img.shields.io/npm/dm/vue-lazyload.svg?style=flat-square)](http://badge.fury.io/js/vue-lazyload)
|
6 | [![npm license](https://img.shields.io/npm/l/vue-lazyload.svg?style=flat-square)](http://badge.fury.io/js/vue-lazyload)
|
7 | [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
|
8 | [![CDNJS version](https://img.shields.io/cdnjs/v/vue-lazyload.svg)](https://cdnjs.com/libraries/vue-lazyload)
|
9 |
|
10 | Vue module for lazyloading images in your applications. Some of goals of this project worth noting include:
|
11 |
|
12 | * Be lightweight, powerful and easy to use
|
13 | * Work on any image type
|
14 | * Add loading class while image is loading
|
15 | * Supports both of Vue 1.0 and Vue 2.0
|
16 |
|
17 |
|
18 |
|
19 | # Table of Contents
|
20 |
|
21 | * [___Demo___](#demo)
|
22 | * [___Requirements___](#requirements)
|
23 | * [___Installation___](#installation)
|
24 | * [___Usage___](#usage)
|
25 | * [___Constructor Options___](#constructor-options)
|
26 | * [___Implementation___](#implementation)
|
27 | * [___Basic___](#basic)
|
28 | * [___Css state___](#css-state)
|
29 | * [___Methods___](#methods)
|
30 | * [__Event hook__](#event-hook)
|
31 | * [__LazyLoadHandler__](#lazyloadhandler)
|
32 | * [__Performance__](#performance)
|
33 | * [___Authors && Contributors___](#authors-&&-Contributors)
|
34 | * [___License___](#license)
|
35 |
|
36 |
|
37 | # Demo
|
38 |
|
39 | [___Demo___](http://hilongjw.github.io/vue-lazyload/)
|
40 |
|
41 | # Requirements
|
42 |
|
43 | - [Vue.js](https://github.com/vuejs/vue) `1.x` or `2.x`
|
44 |
|
45 |
|
46 | # Installation
|
47 |
|
48 | ## npm
|
49 |
|
50 | ```bash
|
51 |
|
52 | $ npm i vue-lazyload -S
|
53 |
|
54 | ```
|
55 |
|
56 | ## CDN
|
57 |
|
58 | CDN: [https://unpkg.com/vue-lazyload/vue-lazyload.js](https://unpkg.com/vue-lazyload/vue-lazyload.js)
|
59 |
|
60 | ```html
|
61 | <script src="https://unpkg.com/vue-lazyload/vue-lazyload.js"></script>
|
62 | <script>
|
63 | Vue.use(VueLazyload)
|
64 | ...
|
65 | </script>
|
66 |
|
67 | ```
|
68 |
|
69 | # Usage
|
70 |
|
71 | main.js:
|
72 |
|
73 | ```javascript
|
74 |
|
75 | import Vue from 'vue'
|
76 | import App from './App.vue'
|
77 | import VueLazyload from 'vue-lazyload'
|
78 |
|
79 | Vue.use(VueLazyload)
|
80 |
|
81 | // or with options
|
82 | Vue.use(VueLazyload, {
|
83 | preLoad: 1.3,
|
84 | error: 'dist/error.png',
|
85 | loading: 'dist/loading.gif',
|
86 | attempt: 1
|
87 | })
|
88 |
|
89 | new Vue({
|
90 | el: 'body',
|
91 | components: {
|
92 | App
|
93 | }
|
94 | })
|
95 | ```
|
96 |
|
97 | template:
|
98 |
|
99 | ```html
|
100 | <ul>
|
101 | <li v-for="img in list">
|
102 | <img v-lazy="img.src" >
|
103 | </li>
|
104 | </ul>
|
105 | ```
|
106 |
|
107 | use `v-lazy-container` work with raw HTML
|
108 |
|
109 | ```html
|
110 | <div v-lazy-container="{ selector: 'img' }">
|
111 | <img data-src="//domain.com/img1.jpg">
|
112 | <img data-src="//domain.com/img2.jpg">
|
113 | <img data-src="//domain.com/img3.jpg">
|
114 | </div>
|
115 | ```
|
116 |
|
117 | custom `error` and `loading` placeholder image
|
118 |
|
119 | ```html
|
120 | <div v-lazy-container="{ selector: 'img', error: 'xxx.jpg', loading: 'xxx.jpg' }">
|
121 | <img data-src="//domain.com/img1.jpg">
|
122 | <img data-src="//domain.com/img2.jpg">
|
123 | <img data-src="//domain.com/img3.jpg">
|
124 | </div>
|
125 | ```
|
126 |
|
127 | ```html
|
128 | <div v-lazy-container="{ selector: 'img' }">
|
129 | <img data-src="//domain.com/img1.jpg" data-error="xxx.jpg">
|
130 | <img data-src="//domain.com/img2.jpg" data-loading="xxx.jpg">
|
131 | <img data-src="//domain.com/img3.jpg">
|
132 | </div>
|
133 | ```
|
134 |
|
135 | ## Constructor Options
|
136 |
|
137 | |key|description|default|options|
|
138 | |:---|---|---|---|
|
139 | | `preLoad`|proportion of pre-loading height|`1.3`|`Number`|
|
140 | |`error`|src of the image upon load fail|`'data-src'`|`String`
|
141 | |`loading`|src of the image while loading|`'data-src'`|`String`|
|
142 | |`attempt`|attempts count|`3`|`Number`|
|
143 | |`listenEvents`|events that you want vue listen for|`['scroll', 'wheel', 'mousewheel', 'resize', 'animationend', 'transitionend', 'touchmove']`| [Desired Listen Events](#desired-listen-events) |
|
144 | |`adapter`| dynamically modify the attribute of element |`{ }`| [Element Adapter](#element-adapter) |
|
145 | |`filter`| the image's listener filter |`{ }`| [Image listener filter](#image-listener-filter) |
|
146 | |`lazyComponent`| lazyload component | `false` | [Lazy Component](#lazy-component)
|
147 | | `dispatchEvent`|trigger the dom event|`false`|`Boolean`|
|
148 | | `throttleWait`|throttle wait|`200`|`Number`|
|
149 | | `observer`|use IntersectionObserver|`false`|`Boolean`|
|
150 | | `observerOptions`|IntersectionObserver options|{ rootMargin: '0px', threshold: 0.1 }|[IntersectionObserver](#intersectionobserver)|
|
151 | | `silent`|do not print debug info|`true`|`Boolean`|
|
152 |
|
153 | ### Desired Listen Events
|
154 |
|
155 | You can configure which events you want vue-lazyload by passing in an array
|
156 | of listener names.
|
157 |
|
158 | ```javascript
|
159 | Vue.use(VueLazyload, {
|
160 | preLoad: 1.3,
|
161 | error: 'dist/error.png',
|
162 | loading: 'dist/loading.gif',
|
163 | attempt: 1,
|
164 | // the default is ['scroll', 'wheel', 'mousewheel', 'resize', 'animationend', 'transitionend']
|
165 | listenEvents: [ 'scroll' ]
|
166 | })
|
167 | ```
|
168 |
|
169 | This is useful if you are having trouble with this plugin resetting itself to loading
|
170 | when you have certain animations and transitions taking place
|
171 |
|
172 |
|
173 | ### Image listener filter
|
174 |
|
175 | dynamically modify the src of image
|
176 |
|
177 | ```javascript
|
178 | Vue.use(vueLazy, {
|
179 | filter: {
|
180 | progressive (listener, options) {
|
181 | const isCDN = /qiniudn.com/
|
182 | if (isCDN.test(listener.src)) {
|
183 | listener.el.setAttribute('lazy-progressive', 'true')
|
184 | listener.loading = listener.src + '?imageView2/1/w/10/h/10'
|
185 | }
|
186 | },
|
187 | webp (listener, options) {
|
188 | if (!options.supportWebp) return
|
189 | const isCDN = /qiniudn.com/
|
190 | if (isCDN.test(listener.src)) {
|
191 | listener.src += '?imageView2/2/format/webp'
|
192 | }
|
193 | }
|
194 | }
|
195 | })
|
196 | ```
|
197 |
|
198 |
|
199 | ### Element Adapter
|
200 |
|
201 | ```javascript
|
202 | Vue.use(vueLazy, {
|
203 | adapter: {
|
204 | loaded ({ bindType, el, naturalHeight, naturalWidth, $parent, src, loading, error, Init }) {
|
205 | // do something here
|
206 | // example for call LoadedHandler
|
207 | LoadedHandler(el)
|
208 | },
|
209 | loading (listender, Init) {
|
210 | console.log('loading')
|
211 | },
|
212 | error (listender, Init) {
|
213 | console.log('error')
|
214 | }
|
215 | }
|
216 | })
|
217 | ```
|
218 |
|
219 | ### IntersectionObserver
|
220 |
|
221 | use [Intersection Observer](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) to to improve performance of a large number of nodes.
|
222 |
|
223 | ```javascript
|
224 | Vue.use(vueLazy, {
|
225 | // set observer to true
|
226 | observer: true,
|
227 |
|
228 | // optional
|
229 | observerOptions: {
|
230 | rootMargin: '0px',
|
231 | threshold: 0.1
|
232 | }
|
233 | })
|
234 | ```
|
235 |
|
236 |
|
237 | ### Lazy Component
|
238 | ```javascript
|
239 | Vue.use(VueLazyload, {
|
240 | lazyComponent: true
|
241 | });
|
242 | ```
|
243 |
|
244 | ```html
|
245 | <lazy-component @show="handler">
|
246 | <img class="mini-cover" :src="img.src" width="100%" height="400">
|
247 | </lazy-component>
|
248 |
|
249 | <script>
|
250 | {
|
251 | ...
|
252 | methods: {
|
253 | handler (component) {
|
254 | console.log('this component is showing')
|
255 | }
|
256 | }
|
257 |
|
258 | }
|
259 | </script>
|
260 | ```
|
261 |
|
262 |
|
263 | ## Implementation
|
264 |
|
265 | ### Basic
|
266 |
|
267 | vue-lazyload will set this img element's `src` with `imgUrl` string
|
268 |
|
269 | ```html
|
270 | <script>
|
271 | export default {
|
272 | data () {
|
273 | return {
|
274 | imgObj: {
|
275 | src: 'http://xx.com/logo.png',
|
276 | error: 'http://xx.com/error.png',
|
277 | loading: 'http://xx.com/loading-spin.svg'
|
278 | },
|
279 | imgUrl: 'http://xx.com/logo.png' // String
|
280 | }
|
281 | }
|
282 | }
|
283 | </script>
|
284 |
|
285 | <template>
|
286 | <div ref="container">
|
287 | <img v-lazy="imgUrl"/>
|
288 | <div v-lazy:background-image="imgUrl"></div>
|
289 |
|
290 | <!-- with customer error and loading -->
|
291 | <img v-lazy="imgObj"/>
|
292 | <div v-lazy:background-image="imgObj"></div>
|
293 |
|
294 | <!-- Customer scrollable element -->
|
295 | <img v-lazy.container ="imgUrl"/>
|
296 | <div v-lazy:background-image.container="img"></div>
|
297 |
|
298 | <!-- srcset -->
|
299 | <img v-lazy="'img.400px.jpg'" data-srcset="img.400px.jpg 400w, img.800px.jpg 800w, img.1200px.jpg 1200w">
|
300 | <img v-lazy="imgUrl" :data-srcset="imgUrl' + '?size=400 400w, ' + imgUrl + ' ?size=800 800w, ' + imgUrl +'/1200.jpg 1200w'" />
|
301 | </div>
|
302 | </template>
|
303 | ```
|
304 |
|
305 | ### CSS state
|
306 |
|
307 | There are three states while img loading
|
308 |
|
309 | `loading` `loaded` `error`
|
310 |
|
311 | ```html
|
312 | <img src="imgUrl" lazy="loading">
|
313 | <img src="imgUrl" lazy="loaded">
|
314 | <img src="imgUrl" lazy="error">
|
315 | ```
|
316 |
|
317 | ```html
|
318 | <style>
|
319 | img[lazy=loading] {
|
320 | /*your style here*/
|
321 | }
|
322 | img[lazy=error] {
|
323 | /*your style here*/
|
324 | }
|
325 | img[lazy=loaded] {
|
326 | /*your style here*/
|
327 | }
|
328 | /*
|
329 | or background-image
|
330 | */
|
331 | .yourclass[lazy=loading] {
|
332 | /*your style here*/
|
333 | }
|
334 | .yourclass[lazy=error] {
|
335 | /*your style here*/
|
336 | }
|
337 | .yourclass[lazy=loaded] {
|
338 | /*your style here*/
|
339 | }
|
340 | </style>
|
341 | ```
|
342 |
|
343 | ## Methods
|
344 |
|
345 | ### Event Hook
|
346 |
|
347 | `vm.$Lazyload.$on(event, callback)`
|
348 | `vm.$Lazyload.$off(event, callback)`
|
349 | `vm.$Lazyload.$once(event, callback)`
|
350 |
|
351 | - `$on` Listen for a custom events `loading`, `loaded`, `error`
|
352 | - `$once` Listen for a custom event, but only once. The listener will be removed once it triggers for the first time.
|
353 | - `$off` Remove event listener(s).
|
354 |
|
355 | #### `vm.$Lazyload.$on`
|
356 |
|
357 | #### Arguments:
|
358 |
|
359 | * `{string} event`
|
360 | * `{Function} callback`
|
361 |
|
362 | #### Example
|
363 |
|
364 | ```javascript
|
365 | vm.$Lazyload.$on('loaded', function ({ bindType, el, naturalHeight, naturalWidth, $parent, src, loading, error }, formCache) {
|
366 | console.log(el, src)
|
367 | })
|
368 | ```
|
369 |
|
370 | #### `vm.$Lazyload.$once`
|
371 |
|
372 | #### Arguments:
|
373 |
|
374 | * `{string} event`
|
375 | * `{Function} callback`
|
376 |
|
377 | #### Example
|
378 |
|
379 | ```javascript
|
380 | vm.$Lazyload.$once('loaded', function ({ el, src }) {
|
381 | console.log(el, src)
|
382 | })
|
383 | ```
|
384 |
|
385 | #### `vm.$Lazyload.$off`
|
386 |
|
387 | If only the event is provided, remove all listeners for that event
|
388 |
|
389 | #### Arguments:
|
390 |
|
391 | * `{string} event`
|
392 | * `{Function} callback`
|
393 |
|
394 | #### Example
|
395 |
|
396 | ```javascript
|
397 | function handler ({ el, src }, formCache) {
|
398 | console.log(el, src)
|
399 | }
|
400 | vm.$Lazyload.$on('loaded', handler)
|
401 | vm.$Lazyload.$off('loaded', handler)
|
402 | vm.$Lazyload.$off('loaded')
|
403 | ```
|
404 |
|
405 | ### LazyLoadHandler
|
406 |
|
407 | `vm.$Lazyload.lazyLoadHandler`
|
408 |
|
409 | Manually trigger lazy loading position calculation
|
410 |
|
411 | #### Example
|
412 |
|
413 | ```javascript
|
414 |
|
415 | this.$Lazyload.lazyLoadHandler()
|
416 |
|
417 | ```
|
418 |
|
419 | ### Performance
|
420 |
|
421 | ```javascript
|
422 | this.$Lazyload.$on('loaded', function (listener) {
|
423 | console.table(this.$Lazyload.performance())
|
424 | })
|
425 | ```
|
426 |
|
427 | ![performance-demo](http://ww1.sinaimg.cn/large/69402bf8gw1fbo62ocvlaj213k09w78w.jpg)
|
428 |
|
429 | ### Dynamic switching pictures
|
430 |
|
431 | ```vue
|
432 | <img v-lazy="lazyImg" :key="lazyImg.src">
|
433 | ```
|
434 |
|
435 |
|
436 | # Authors && Contributors
|
437 |
|
438 | - [hilongjw](https://github.com/hilongjw)
|
439 | - [imcvampire](https://github.com/imcvampire)
|
440 | - [darrynten](https://github.com/darrynten)
|
441 | - [biluochun](https://github.com/biluochun)
|
442 | - [whwnow](https://github.com/whwnow)
|
443 | - [Leopoldthecoder](https://github.com/Leopoldthecoder)
|
444 | - [michalbcz](https://github.com/michalbcz)
|
445 | - [blue0728](https://github.com/blue0728)
|
446 | - [JounQin](https://github.com/JounQin)
|
447 | - [llissery](https://github.com/llissery)
|
448 | - [mega667](https://github.com/mega667)
|
449 | - [RobinCK](https://github.com/RobinCK)
|
450 | - [GallenHu](https://github.com/GallenHu)
|
451 |
|
452 | # License
|
453 |
|
454 | [The MIT License](http://opensource.org/licenses/MIT)
|