-
Notifications
You must be signed in to change notification settings - Fork 2
/
vue-lazyload-akamai.js
111 lines (99 loc) · 3.29 KB
/
vue-lazyload-akamai.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/**
* Read more about lazyLoad using IntersectionObserver
* https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video/
* --
* Polyfill: https://github.com/w3c/IntersectionObserver/tree/master/polyfill
*/
import imageConverter from 'akamai-image-converter'
const plugin = {
/**
* available options:
* + useWebp: Boolean
* + quality: Number
* + height, width: Number
* + fallback: String
*/
install: (Vue, options = {}) => {
const isSupportWebp = (document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0)
const DEFAULT_TIMEOUT = 300
const _swapImage = (targetEl, params) => {
// data original
let dataSrc = targetEl.dataset.src
// put akamai image coverter here
if (params.useWebp && isSupportWebp) {
dataSrc = imageConverter._withOutputFormat(dataSrc, 'webp')
}
let localQuality = targetEl.dataset.quality
if (localQuality) {
dataSrc = imageConverter._withQuality(dataSrc, localQuality)
} else if (params.quality) {
dataSrc = imageConverter._withQuality(dataSrc, params.quality)
}
let localWidth = targetEl.dataset.width
let localHeight = targetEl.dataset.height
if (localWidth && localHeight) {
dataSrc = imageConverter._withDimension(dataSrc, localWidth, localHeight)
} else if (params.width && param.height) {
dataSrc = imageConverter._withDimension(dataSrc, params.width, params.height)
}
// async load image
var newImage = new Image()
newImage.src = dataSrc
// when success
newImage.onload = () => {
if (dataSrc) {
let timeout = params.timeout || DEFAULT_TIMEOUT
// swap image here
setTimeout(() => {
targetEl.src = dataSrc
}, timeout)
}
}
// data fallback image
const localFallback = targetEl.dataset.err
// when image failed to fetched
newImage.onerror = () => {
if (localFallback) {
targetEl.src = localFallback
} else if (params.fallback) {
targetEl.src = params.fallback
}
}
}
const _initObserver = (el, params) => {
const lazyImageObserver = new IntersectionObserver(function (entries, observer) {
entries.forEach(function (entry) {
// when intersecting
if (entry.isIntersecting) {
const lazyImage = entry.target
_swapImage(lazyImage, params)
// remove observer after done
lazyImageObserver.unobserve(lazyImage)
}
})
})
// init observer
lazyImageObserver.observe(el)
}
// create vue directive for easier use in components
Vue.directive('lazyimg', {
bind (el) {
// using global place holder if exist
if (options.placeholder){
el.src = options.placeholder
}
// basic flow: read from data-src attribute than move to src attr
if ('IntersectionObserver' in window) {
_initObserver(el, options)
} else {
// fallback when IntersectionObserver not supported
_swapImage(el, options)
}
},
update (el) {
// fired when you replace with value
}
})
}
}
export default plugin