152 lines
3.0 KiB
Vue
152 lines
3.0 KiB
Vue
<template>
|
|
<view :style="[viewStyle]" :class="{'custom-image': true, 'image-round': round}" @click="onClick">
|
|
<image v-if="!error" :src="src" :mode="mode" :lazy-load="lazyLoad" class="image" :show-menu-by-longpress="showMenuByLongpress"
|
|
@load="onLoaded" @error="onErrored"></image>
|
|
<view v-if="loading && showLoading" class="loading-wrap image">
|
|
<slot v-if="useLoadingSlot" name="loading"></slot>
|
|
<u-icon color="#aaa" v-else name="photo-fill" size="45"></u-icon>
|
|
</view>
|
|
<view v-if="error && showError" class="error-wrap image">
|
|
<slot v-if="useErrorSlot" name="error"></slot>
|
|
<u-icon color="#aaa" v-else name="error-circle-fill" size="45"></u-icon>
|
|
<text class="sm">加载失败</text>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
props: {
|
|
src: {
|
|
type: String,
|
|
|
|
},
|
|
round: Boolean,
|
|
width: {
|
|
type: null
|
|
},
|
|
height: {
|
|
type: null
|
|
},
|
|
radius: null,
|
|
lazyLoad: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
useErrorSlot: Boolean,
|
|
useLoadingSlot: Boolean,
|
|
showMenuByLongpress: Boolean,
|
|
mode: {
|
|
type: String,
|
|
default: 'scaleToFill'
|
|
},
|
|
showError: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
showLoading: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
customStyle: {
|
|
type: Object,
|
|
default: () => {}
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
error: false,
|
|
loading: true,
|
|
viewStyle: {}
|
|
}
|
|
},
|
|
created() {
|
|
this.setStyle();
|
|
},
|
|
methods: {
|
|
|
|
setStyle() {
|
|
const {
|
|
width,
|
|
height,
|
|
radius
|
|
} = this
|
|
let style = {};
|
|
|
|
if (width) {
|
|
style.width = width
|
|
}
|
|
|
|
if (height) {
|
|
style.height = height
|
|
}
|
|
|
|
if (radius) {
|
|
style['overflow'] = 'hidden'
|
|
style['border-radius'] = radius
|
|
}
|
|
this.viewStyle = style;
|
|
if(this.customStyle) {
|
|
this.viewStyle = Object.assign(this.viewStyle, this.customStyle)
|
|
}
|
|
},
|
|
onLoaded(event) {
|
|
this.loading = false
|
|
this.$emit('load', event.detail);
|
|
},
|
|
onErrored(event) {
|
|
this.error = false
|
|
this.loading = true
|
|
this.$emit('error', event.detail);
|
|
},
|
|
onClick(event) {
|
|
this.$emit('click', event.detail);
|
|
}
|
|
},
|
|
watch: {
|
|
src() {
|
|
this.error = false
|
|
this.loading = true
|
|
},
|
|
width() {
|
|
this.setStyle()
|
|
},
|
|
height() {
|
|
this.setStyle()
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.custom-image {
|
|
position: relative;
|
|
display: block;
|
|
width: 100%;
|
|
height: 100%;
|
|
&.image-round {
|
|
overflow: hidden;
|
|
border-radius: 50%;
|
|
}
|
|
.image {
|
|
display: block;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.loading-wrap,
|
|
.error-wrap {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: #969799;
|
|
font-size: 28rpx;
|
|
background-color: #f7f8fa;
|
|
}
|
|
}
|
|
</style>
|