172 lines
4.2 KiB
Vue
172 lines
4.2 KiB
Vue
<template>
|
||
<view class="easy-loadimage" :id="uid">
|
||
<image class="origin-img" :src="imageSrc" mode="aspectFill" v-if="loadImg&&!isLoadError" v-show="showImg"
|
||
:class="{'no-transition':!openTransition,'show-transition':showTransition&&openTransition}"
|
||
@load="handleImgLoad" @error="handleImgError">
|
||
</image>
|
||
<view class="loadfail-img" v-else-if="isLoadError"></view>
|
||
<view :class="['loading-img','spin-circle',loadingMode]" v-show="!showImg&&!isLoadError"></view>
|
||
</view>
|
||
</template>
|
||
<script>
|
||
import { throttle } from '@/libs/uniApi';
|
||
// 生成全局唯一id
|
||
function generateUUID() {
|
||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||
let r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
|
||
return v.toString(16);
|
||
})
|
||
}
|
||
export default{
|
||
props:{
|
||
imageSrc:{
|
||
type: String,
|
||
},
|
||
mode:{
|
||
type: String,
|
||
},
|
||
loadingMode:{
|
||
type: String,
|
||
default:'looming-gray'
|
||
},
|
||
openTransition:{
|
||
type: Boolean,
|
||
default:true,
|
||
},
|
||
viewHeight:{
|
||
type:Number,
|
||
default() {
|
||
return uni.getSystemInfoSync().windowHeight;
|
||
}
|
||
}
|
||
},
|
||
data(){
|
||
const that = this;
|
||
return {
|
||
uid: 'uid-' + generateUUID(),
|
||
loadImg: false,
|
||
showImg: false,
|
||
isLoadError: false,
|
||
borderLoaded: 0,
|
||
showTransition: false,
|
||
scrollFn: throttle(function() {
|
||
// 加载img时才执行滚动监听判断是否可加载
|
||
if (that.loadImg || that.isLoadError) return;
|
||
const id = that.uid
|
||
const query = uni.createSelectorQuery().in(that);
|
||
query.select('#' + id).boundingClientRect(data => {
|
||
if (!data) return;
|
||
if (data.top - that.viewHeight < 0) {
|
||
that.loadImg = !!that.imageSrc;
|
||
that.isLoadError = !that.loadImg;
|
||
}
|
||
}).exec()
|
||
}, 200)
|
||
}
|
||
},
|
||
methods:{
|
||
init() {
|
||
this.$nextTick(this.onScroll)
|
||
},
|
||
handleBorderLoad(){
|
||
this.borderLoaded = 1;
|
||
},
|
||
handleBorderError(){
|
||
this.borderLoaded = 2;
|
||
},
|
||
handleImgLoad(e) {
|
||
this.showImg = true;
|
||
setTimeout(() => {
|
||
this.showTransition = true
|
||
}, 50)
|
||
},
|
||
handleImgError(e) {
|
||
this.isLoadError = true;
|
||
},
|
||
onScroll() {
|
||
this.scrollFn();
|
||
},
|
||
},
|
||
mounted() {
|
||
this.init()
|
||
uni.$on('scroll', this.scrollFn);
|
||
this.onScroll()
|
||
},
|
||
beforeDestroy() {
|
||
uni.$off('scroll', this.scrollFn);
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* 官方优化图片tips */
|
||
image{
|
||
/* will-change: transform */
|
||
}
|
||
/* 渐变过渡效果处理 */
|
||
image.origin-img{
|
||
width: 100%;
|
||
height: 100%;
|
||
opacity: 0.3;
|
||
max-height: 360rpx;
|
||
}
|
||
image.origin-img.show-transition{
|
||
/* transition: opacity .5s; */
|
||
opacity: 1;
|
||
}
|
||
image.origin-img.no-transition{
|
||
opacity: 1;
|
||
}
|
||
/* 加载失败、加载中的占位图样式控制 */
|
||
.loadfail-img{
|
||
height: 100%;
|
||
background: url('~@/static/easy-loadimage/loadfail.png') no-repeat center;
|
||
background-size: 50%;
|
||
}
|
||
.loading-img{
|
||
height: 100%;
|
||
}
|
||
/* 转圈 */
|
||
.spin-circle{
|
||
background: url('~@/static/easy-loadimage/loading.gif') no-repeat center;
|
||
background-size: 60%;
|
||
}
|
||
/* 动态灰色若隐若现 */
|
||
.looming-gray{
|
||
animation: looming-gray 1s infinite linear;
|
||
background-color: #e3e3e3;
|
||
}
|
||
@keyframes looming-gray{
|
||
0% {background-color:#e3e3e3aa;}
|
||
50% {background-color:#e3e3e3;}
|
||
100% {background-color:#e3e3e3aa;}
|
||
}
|
||
/* 骨架屏1 */
|
||
.skeleton-1{
|
||
background-color: #e3e3e3;
|
||
background-image: linear-gradient(100deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0) 80%);
|
||
background-size: 100rpx 100%;
|
||
background-repeat: repeat-y;
|
||
background-position:0 0;
|
||
animation: skeleton-1 .6s infinite;
|
||
}
|
||
@keyframes skeleton-1 {
|
||
to {
|
||
background-position: 200% 0;
|
||
}
|
||
}
|
||
/* 骨架屏2 */
|
||
.skeleton-2{
|
||
background-image: linear-gradient(-90deg, #fefefe 0%, #e6e6e6 50%,#fefefe 100%);
|
||
background-size: 400% 400%;
|
||
background-position:0 0;
|
||
animation: skeleton-2 1.2s ease-in-out infinite;
|
||
}
|
||
@keyframes skeleton-2{
|
||
to {
|
||
background-position: -135% 0;
|
||
}
|
||
}
|
||
</style>
|
||
|