mirror of
https://github.com/gosticks/vue-webshop.git
synced 2025-10-16 12:05:40 +00:00
Added async image loading with not found and loading indication
This commit is contained in:
parent
8fe515afea
commit
30f97237f5
77
src/components/UIComponents/OxyImage.vue
Normal file
77
src/components/UIComponents/OxyImage.vue
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// OxyImagge helps to load images asynch
|
||||||
|
// adds loading indicator
|
||||||
|
// if laod fails also adds a image not found placeholder
|
||||||
|
<template>
|
||||||
|
<div class="oxy-image-wrapper">
|
||||||
|
<oxy-spinner v-if="!isLoaded"></oxy-spinner>
|
||||||
|
<template :ref="oxyImageHolder" v-if="!notFound">
|
||||||
|
<img :src="src" />
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<img :src="notFoundImage" />
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import OxySpinner from './OxySpinner'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
OxySpinner
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
notFoundImage: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'static/img/image_not_found.svg'
|
||||||
|
},
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'static/img/image_not_found.svg'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted () {
|
||||||
|
this.image = new Image()
|
||||||
|
this.image.onload = this.loadCompleted
|
||||||
|
this.image.onerror = this.loadError
|
||||||
|
this.image.src = this.src
|
||||||
|
},
|
||||||
|
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
isLoaded: false,
|
||||||
|
notFound: true,
|
||||||
|
image: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
loadError: function (event) {
|
||||||
|
console.warn('Failed to laod ressource', event)
|
||||||
|
this.isLoaded = true
|
||||||
|
this.notFound = true
|
||||||
|
},
|
||||||
|
loadCompleted: function (success) {
|
||||||
|
console.log('Image loaded', success, this)
|
||||||
|
this.isLoaded = true
|
||||||
|
this.notFound = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.oxy-image-wrapper {
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.oxy-image-wrapper img {
|
||||||
|
display: block;
|
||||||
|
max-height: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="item product">
|
<div class="item product">
|
||||||
<p class="product-image-wrapper">
|
<p class="product-image-wrapper">
|
||||||
<img class="product-thumb" :src="product.thumb">
|
<oxy-image class="product-thumb" :src="product.thumb"></oxy-image>
|
||||||
</p>
|
</p>
|
||||||
<p class="product-name">{{product.title}}</p>
|
<p class="product-name">{{product.title}}</p>
|
||||||
<oxy-rating :v-if="product.rating" :rating="product.rating"></oxy-rating>
|
<oxy-rating :v-if="product.rating" :rating="product.rating"></oxy-rating>
|
||||||
@ -13,9 +13,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import OxyImage from '../UIComponents/OxyImage'
|
||||||
import OxyRating from './OxyRating.vue'
|
import OxyRating from './OxyRating.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
OxyImage,
|
||||||
OxyRating
|
OxyRating
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// this components is based on css styles by lukehaas https://github.com/lukehaas
|
// this components is based on css styles by lukehaas https://github.com/lukehaas
|
||||||
<template>
|
<template>
|
||||||
<div class="loader" :class="{isActive : play}">Loading...</div>
|
<div class="loader" :class="{play : isActive}">Loading...</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -15,13 +15,15 @@ export default {
|
|||||||
this.isActive = false
|
this.isActive = false
|
||||||
},
|
},
|
||||||
continue () {
|
continue () {
|
||||||
this.isActive
|
this.isActive = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style lang="scss">
|
||||||
|
$spinner-color: rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
.loader,
|
.loader,
|
||||||
.loader:after {
|
.loader:after {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
@ -33,9 +35,9 @@ export default {
|
|||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
position: relative;
|
position: relative;
|
||||||
text-indent: -9999em;
|
text-indent: -9999em;
|
||||||
border-top: 1.1em solid rgba(255, 255, 255, 0.2);
|
border-top: 1.1em solid $spinner-color;
|
||||||
border-right: 1.1em solid rgba(255, 255, 255, 0.2);
|
border-right: 1.1em solid $spinner-color;
|
||||||
border-bottom: 1.1em solid rgba(255, 255, 255, 0.2);
|
border-bottom: 1.1em solid $spinner-color;
|
||||||
border-left: 1.1em solid #ffffff;
|
border-left: 1.1em solid #ffffff;
|
||||||
-webkit-transform: translateZ(0);
|
-webkit-transform: translateZ(0);
|
||||||
-ms-transform: translateZ(0);
|
-ms-transform: translateZ(0);
|
||||||
|
|||||||
1
static/img/image_not_found.svg
Normal file
1
static/img/image_not_found.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><title>image_not_found</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><rect width="512" height="512" style="fill:none"/><text transform="translate(150.83 191.81)" style="font-size:76.77847290039062px;fill:#ededed;font-family:Helvetica-Bold, Helvetica;font-weight:700">IMAGE<tspan x="0" y="92.13">NOT</tspan><tspan x="0" y="184.27">FOUND</tspan></text><rect x="106.84" y="133.53" width="13.63" height="248.5" style="fill:#ededed"/></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 540 B |
Loading…
Reference in New Issue
Block a user