implement lazy images
This commit is contained in:
parent
9d779a203c
commit
436c8c05aa
47
routes/_components/LazyImage.html
Normal file
47
routes/_components/LazyImage.html
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<div class="lazy-image"
|
||||||
|
style="width: {{width}}px; height: {{height}}px; background: {{background}};">
|
||||||
|
{{#if displaySrc}}
|
||||||
|
<img
|
||||||
|
class="{{hidden ? 'hidden' : ''}} {{className || ''}}"
|
||||||
|
aria-hidden="{{ariaHidden || ''}}"
|
||||||
|
alt="{{alt || ''}}"
|
||||||
|
src="{{displaySrc}}"
|
||||||
|
:width
|
||||||
|
:height
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.lazy-image {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.lazy-image img {
|
||||||
|
transition: opacity 0.2s linear;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
oncreate() {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
let img = new Image()
|
||||||
|
let src = this.get('src')
|
||||||
|
let fallback = this.get('fallback')
|
||||||
|
img.onload = () => {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.set({
|
||||||
|
displaySrc: src,
|
||||||
|
hidden: true
|
||||||
|
})
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.set({hidden: false})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
img.onerror = () => {
|
||||||
|
this.set({displaySrc: fallback})
|
||||||
|
}
|
||||||
|
img.src = src
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -17,14 +17,15 @@
|
||||||
playsinline
|
playsinline
|
||||||
/>
|
/>
|
||||||
{{else}}
|
{{else}}
|
||||||
<img class="{{class}} {{imageError ? 'image-error' : ''}}"
|
<LazyImage
|
||||||
alt="{{label}}"
|
alt="{{label}}"
|
||||||
src="{{imageError ? oneTransparentPixel : staticSrc}}"
|
src="{{staticSrc}}"
|
||||||
width="{{width}}"
|
fallback="{{oneTransparentPixel}}"
|
||||||
height="{{height}}"
|
:width
|
||||||
on:imgLoad="set({imageLoaded: true})"
|
:height
|
||||||
on:imgLoadError="set({imageError: true})"
|
background="var(--loading-bg)"
|
||||||
/>
|
className="{{class}}"
|
||||||
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<PlayVideoIcon className="{{playing ? 'hidden' : ''}}"/>
|
<PlayVideoIcon className="{{playing ? 'hidden' : ''}}"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -39,9 +40,9 @@
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import { mouseover } from '../_utils/events'
|
import { mouseover } from '../_utils/events'
|
||||||
import { imgLoad, imgLoadError } from '../_utils/events'
|
|
||||||
import PlayVideoIcon from './PlayVideoIcon.html'
|
import PlayVideoIcon from './PlayVideoIcon.html'
|
||||||
import { ONE_TRANSPARENT_PIXEL } from '../_static/media'
|
import { ONE_TRANSPARENT_PIXEL } from '../_static/media'
|
||||||
|
import LazyImage from './LazyImage.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -50,15 +51,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
events: {
|
events: {
|
||||||
mouseover,
|
mouseover
|
||||||
imgLoad,
|
|
||||||
imgLoadError
|
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
oneTransparentPixel: ONE_TRANSPARENT_PIXEL
|
oneTransparentPixel: ONE_TRANSPARENT_PIXEL
|
||||||
}),
|
}),
|
||||||
components: {
|
components: {
|
||||||
PlayVideoIcon
|
PlayVideoIcon,
|
||||||
|
LazyImage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
|
@ -6,13 +6,14 @@
|
||||||
style="width: {{inlineWidth}}px; height: {{inlineHeight}}px;"
|
style="width: {{inlineWidth}}px; height: {{inlineHeight}}px;"
|
||||||
>
|
>
|
||||||
<PlayVideoIcon />
|
<PlayVideoIcon />
|
||||||
<img alt="{{media.description || ''}}"
|
<LazyImage
|
||||||
src="{{imageError ? oneTransparentPixel : media.preview_url}}"
|
alt="{{media.description}}"
|
||||||
width="{{inlineWidth}}"
|
src="{{media.preview_url}}"
|
||||||
height="{{inlineHeight}}"
|
fallback="{{oneTransparentPixel}}"
|
||||||
class="{{noNativeWidthHeight ? 'no-native-width-height' : ''}} {{imageError ? 'image-error' : ''}}"
|
width="{{inlineWidth}}"
|
||||||
on:imgLoad="set({imageLoaded: true})"
|
height="{{inlineHeight}}"
|
||||||
on:imgLoadError="set({imageError: true})"
|
background="var(--loading-bg)"
|
||||||
|
className="{{noNativeWidthHeight ? 'no-native-width-height' : ''}}"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
{{else}}
|
{{else}}
|
||||||
|
@ -48,25 +49,23 @@
|
||||||
playing="{{mouseover}}"
|
playing="{{mouseover}}"
|
||||||
/>
|
/>
|
||||||
{{else}}
|
{{else}}
|
||||||
<img class="{{!imageLoaded ? 'image-loading' : ''}} {{imageError ? 'image-error' : ''}} {{noNativeWidthHeight ? 'no-native-width-height' : ''}}"
|
<LazyImage
|
||||||
on:imgLoad="set({imageLoaded: true})"
|
alt="{{media.description}}"
|
||||||
on:imgLoadError="set({imageError: true})"
|
src="{{media.preview_url}}"
|
||||||
alt="{{media.description || ''}}"
|
fallback="{{oneTransparentPixel}}"
|
||||||
src="{{imageError ? oneTransparentPixel : media.preview_url}}"
|
width="{{inlineWidth}}"
|
||||||
width="{{inlineWidth}}"
|
height="{{inlineHeight}}"
|
||||||
height="{{inlineHeight}}"
|
background="var(--loading-bg)"
|
||||||
|
className="{{noNativeWidthHeight ? 'no-native-width-height' : ''}}"
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</button>
|
</button>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<style>
|
<style>
|
||||||
:global(.status-media img.image-loading, .status-media img.image-error) {
|
|
||||||
background: var(--loading-bg);
|
|
||||||
}
|
|
||||||
:global(.status-media video, .status-media img) {
|
:global(.status-media video, .status-media img) {
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
.no-native-width-height {
|
:global(.no-native-width-height) {
|
||||||
background-color: var(--mask-bg);
|
background-color: var(--mask-bg);
|
||||||
}
|
}
|
||||||
.play-video-button {
|
.play-video-button {
|
||||||
|
@ -86,24 +85,28 @@
|
||||||
cursor: zoom-in;
|
cursor: zoom-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.status-media video, .status-media img) {
|
:global(.status-media video, .status-media img, .status-media .lazy-image,
|
||||||
|
.status-media .show-image-button, .status-media .non-autoplay-gifv,
|
||||||
|
.status-media .play-video-button) {
|
||||||
max-width: calc(100vw - 40px);
|
max-width: calc(100vw - 40px);
|
||||||
}
|
}
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
:global(.status-media video, .status-media img) {
|
:global(.status-media video, .status-media img, .status-media .lazy-image,
|
||||||
|
.status-media .show-image-button, .status-media .non-autoplay-gifv,
|
||||||
|
.status-media .play-video-button) {
|
||||||
max-width: calc(100vw - 20px);
|
max-width: calc(100vw - 20px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import { DEFAULT_MEDIA_WIDTH, DEFAULT_MEDIA_HEIGHT } from '../../_static/media'
|
import { DEFAULT_MEDIA_WIDTH, DEFAULT_MEDIA_HEIGHT } from '../../_static/media'
|
||||||
import { imgLoad, imgLoadError } from '../../_utils/events'
|
|
||||||
import { importDialogs } from '../../_utils/asyncModules'
|
import { importDialogs } from '../../_utils/asyncModules'
|
||||||
import { mouseover } from '../../_utils/events'
|
import { mouseover } from '../../_utils/events'
|
||||||
import NonAutoplayGifv from '../NonAutoplayGifv.html'
|
import NonAutoplayGifv from '../NonAutoplayGifv.html'
|
||||||
import PlayVideoIcon from '../PlayVideoIcon.html'
|
import PlayVideoIcon from '../PlayVideoIcon.html'
|
||||||
import { ONE_TRANSPARENT_PIXEL } from '../../_static/media'
|
import { ONE_TRANSPARENT_PIXEL } from '../../_static/media'
|
||||||
import { store } from '../../_store/store'
|
import { store } from '../../_store/store'
|
||||||
|
import LazyImage from '../LazyImage.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -143,13 +146,12 @@
|
||||||
}),
|
}),
|
||||||
store: () => store,
|
store: () => store,
|
||||||
events: {
|
events: {
|
||||||
imgLoad,
|
|
||||||
imgLoadError,
|
|
||||||
mouseover
|
mouseover
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
NonAutoplayGifv,
|
NonAutoplayGifv,
|
||||||
PlayVideoIcon
|
PlayVideoIcon,
|
||||||
|
LazyImage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
Loading…
Reference in a new issue