You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

202 lines
4.6 KiB
Vue

1 year ago
<template>
<view @click="click" class="tm-images overflow fulled " :class="[round=='rounded'?'rounded':`round-${round}`]">
<view class="fulled fulled-height tm-images-load flex-center">
<view class="d-inline-block load">
<text v-if="isLoad" class="iconfont icon-loading text-size-n text-grey"></text>
</view>
<view class="d-inline-block" v-if="isError">
<slot name="error">
<text class="iconfont icon-exclamationcircle-f text-size-xl text-grey-lighten-2"></text>
</slot>
</view>
<image v-show="!isLoad" @error="error"
:class="[round=='rounded'?'rounded':`round-${round}`]"
:style="{
width:w+'px',
height:h+'px'
}"
@load="loadPic" :src="src_path" :mode="model"></image>
</view>
</view>
</template>
<script>
/**
* 图片
* @property {Function} load 加载成功时触发返回图片宽高
* @property {Function} click 点击图片事件返回图片地址参数
* @property {Function} error 图片加载出错时触发
* @property {String} src = [] 默认"",必填图片地址测试图片https://picsum.photos/300
* @property {Number} width = [] 默认0,宽度非必填,单位rpx
* @property {Number} height = [] 默认0,高度非必填,单位rpx
* @property {Number} round = [] 默认0,圆角非必填
* @property {Boolean|String} previmage = [true|false] 默认true,点击图片是否预览
* @property {String} model = [scaleToFill|aspectFit|aspectFill|widthFix|heightFix|top|bottom|center|left|right|top left|top right|bottom left|bottom right] 默认scaleToFill,图片展现模式同官方
* @example <tm-images src="https://picsum.photos/300"></tm-images>
*/
export default {
name: "tm-images",
props: {
src: {
type: String,
default: ""
},
//自动,宽度撑满容器宽度,高度自动。
// 自定宽度,
width: {
type: Number,
default: 0
},
// 自定高度。
height: {
type: Number,
default: 0
},
// 是否开启预览模式,即点击图片可以预览。
previmage: {
type: Boolean | String,
default: true
},
model: {
type: String,
default: 'scaleToFill'
},
round: {
type: Number|String,
default: 0
}
},
data() {
return {
w: 0,
h: 0,
isLoad:false,
isError:false
};
},
computed:{
w_px:function(){
return uni.upx2px(this.width);
},
h_px:function(){
return uni.upx2px(this.height);
},
src_path:function(){
if(
this.src.substring(0,4)=='http'||
this.src.substring(0,4)=='blob'||
this.src.substring(0,5)=='https'||
this.src.substring(0,3)=='ftp'||
this.src.indexOf('data:image')>-1
){
return this.src;
}
return '/'+this.src;
}
},
mounted() {
this.isLoad = true;
},
methods: {
error(e) {
this.isLoad = false;
this.isError = true;
this.$emit('error', e);
},
async loadPic(e) {
let wh = e.detail;
this.isLoad = false;
this.isError = false;
this.$nextTick(async function(){
this.$Querey(".tm-images",this,30).then(tb=>{
let sw = tb[0].width||wh.width;
let sh = tb[0].height||wh.height;
let bl = wh.width / wh.height;
if (this.w_px == 0 && this.h_px == 0) {
this.w = sw;
this.h = sw / bl;
this.$emit('load', {
width: this.w,
height: this.h
})
return;
}
if (this.w_px == 0 && this.h_px > 0) {
this.w = this.h_px * bl;
this.h = this.h_px
this.$emit('load', {
width: this.w,
height: this.h
})
return;
}
if (this.w_px > 0 && this.h_px == 0) {
this.w = this.w_px;
this.h = this.w_px / bl
this.$emit('load', {
width: this.w,
height: this.h
})
return;
}
if (this.w_px > 0 && this.h_px > 0) {
this.w = this.w_px;
this.h = this.h_px;
this.$emit('load', {
width: this.w,
height: this.h
})
return;
}
})
})
},
click(e) {
this.$emit("click", this.src_path);
if (this.previmage&&!this.isError) {
uni.previewImage({
current: this.src_path,
urls: [this.src_path],
fail:(res)=>{
}
})
}
}
},
}
</script>
<style lang="scss" scoped>
.tm-images{
line-height: 0;
.tm-images-load{
min-width: 60rpx;
min-height: 60rpx;
.load{
animation: xhRote 0.8s infinite linear;
}
}
}
@keyframes xhRote{
0%{
transform: rotate(0deg);
}
100%{
transform: rotate(360deg);
}
}
</style>