Files
t/components/thorui/tui-lazyload-img/tui-lazyload-img.vue
T
2025-03-21 09:38:06 +08:00

194 lines
4.1 KiB
Vue

<template>
<view class="tui-lazyload__box"
:style="{backgroundColor:placeholder?'transparent':backgroundColor,width:width,borderRadius:radius}"
@tap="handleClick">
<image class="tui-lazyload__img"
:class="{'tui-img__hidden':!placeholder && fadeShow && !show,'tui-img__appear':show && !placeholder && fadeShow}"
:style="{height:height,borderRadius:radius}" :id="uid" :src="show?src:placeholder" :mode="mode" :webp="webp"
:show-menu-by-longpress="showMenuByLongpress" :draggable="draggable" @load="load" @error="error">
</image>
<slot></slot>
</view>
</template>
<script>
export default {
name: "tui-lazyload-img",
props: {
//图片路径
src: {
type: String,
default: ''
},
//占位图路径
placeholder: {
type: String,
default: ''
},
//占位背景色,placeholder有值时失效
backgroundColor: {
type: String,
default: '#E7E7E7'
},
//图片的裁剪模式,参考image组件mode属性
mode: {
type: String,
default: 'widthFix'
},
//图片显示动画效果,无占位图时有效
fadeShow: {
type: Boolean,
default: true
},
//默认不解析 webP 格式,只支持网络资源 微信小程序2.9.0
webp: {
type: Boolean,
default: false
},
//开启长按图片显示识别小程序码菜单 微信小程序2.7.0
showMenuByLongpress: {
type: Boolean,
default: false
},
//鼠标长按是否能拖动图片 仅H5平台 3.1.1+ 有效
draggable: {
type: Boolean,
default: true
},
//图片宽度
width: {
type: String,
default: '340rpx'
},
//图片高度,如果高度设置为auto,mode值需要设置为widthFix
height: {
type: String,
default: '340rpx'
},
//图片圆角值,如:10rpx
radius: {
type: String,
default: '0'
},
//节点布局区域的下边界,目标节点区域以下 bottom(px) 时,就会触发回调函数
bottom: {
type: [Number, String],
default: 50
},
//是否停止监听,设置为true时回调函数将不再触发
disconnect: {
type: Boolean,
default: false
},
//图片在列表中的索引值
index: {
type: Number,
default: 0
}
},
data() {
return {
show: false,
observer: null,
uid: null
};
},
watch: {
disconnect(val) {
if (val) {
this.removeObserver()
}
}
},
created() {
this.uid = this.unique() + this.index;
},
mounted() {
if (!this.disconnect) {
this.initObserver()
} else {
this.show = true;
}
},
beforeDestroy() {
this.removeObserver()
},
methods: {
unique: function(n) {
n = n || 6;
let rnd = '';
for (let i = 0; i < n; i++)
rnd += Math.floor(Math.random() * 10);
return 'tui_' + new Date().getTime() + rnd;
},
removeObserver() {
if (this.observer) {
this.observer.disconnect()
this.observer = null;
}
},
initObserver() {
if (this.observer || this.show) return;
try {
let element = this.uid ? `#${this.uid}` : '.tui-lazyload__img';
const observer = uni.createIntersectionObserver(this)
observer.relativeToViewport({
bottom: Number(this.bottom) || 50
}).observe(element, (res) => {
if (res.intersectionRatio > 0 && !this.show) {
this.show = true;
this.removeObserver()
}
})
this.observer = observer
} catch (e) {
//TODO handle the exception
this.show = true;
this.removeObserver()
}
},
error(e) {
if (!this.show) return;
this.$emit('error', {
detail: e.detail,
index: this.index
})
},
load(e) {
if (!this.show) return;
this.$emit('load', {
detail: e.detail,
index: this.index
})
},
handleClick(e) {
this.$emit('click', {
index: this.index
})
}
}
}
</script>
<style scoped>
.tui-lazyload__box {
display: inline-block;
position: relative;
}
.tui-lazyload__img {
width: 100%;
display: block;
flex-shrink: 0;
transition: opacity .3s linear;
}
.tui-img__hidden {
opacity: 0;
}
.tui-img__appear {
opacity: 1;
}
</style>