255 lines
37 KiB
Vue
255 lines
37 KiB
Vue
|
<template>
|
|||
|
<view class="tn-lazy-load-class tn-lazy-load">
|
|||
|
<view
|
|||
|
class="tn-lazy-load__item"
|
|||
|
:class="[`tn-lazy-load__item--${elIndex}`]"
|
|||
|
:style="[lazyLoadItemStyle]"
|
|||
|
>
|
|||
|
<view class="tn-lazy-load__item__content">
|
|||
|
<image
|
|||
|
v-if="!error"
|
|||
|
class="tn-lazy-load__item__image"
|
|||
|
:style="[imageStyle]"
|
|||
|
:src="show ? image : loadingImg"
|
|||
|
:mode="imgMode"
|
|||
|
@load="handleImgLoaded"
|
|||
|
@error="handleImgError"
|
|||
|
@tap="handleImgClick"
|
|||
|
></image>
|
|||
|
<image
|
|||
|
v-else
|
|||
|
class="tn-lazy-load__item__image tn-lazy-load__item__image--error"
|
|||
|
:style="[imageStyle]"
|
|||
|
:src="errorImg"
|
|||
|
:mode="imgMode"
|
|||
|
@load="handleErrorImgLoaded"
|
|||
|
@tap="handleImgClick"
|
|||
|
></image>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</view>
|
|||
|
</template>
|
|||
|
|
|||
|
<script>
|
|||
|
export default {
|
|||
|
name: 'tn-lazy-load',
|
|||
|
props: {
|
|||
|
// 组件标识
|
|||
|
index: {
|
|||
|
type: [String, Number],
|
|||
|
default: ''
|
|||
|
},
|
|||
|
// 待显示的图片地址
|
|||
|
image: {
|
|||
|
type: String,
|
|||
|
default: ''
|
|||
|
},
|
|||
|
// 图片裁剪模式
|
|||
|
imgMode: {
|
|||
|
type: String,
|
|||
|
default: 'scaleToFill'
|
|||
|
},
|
|||
|
// 占位图片路径
|
|||
|
loadingImg: {
|
|||
|
type: String,
|
|||
|
default: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQCAMAAAC3Ycb+AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OUM0QjNBQjkyQUQ2MTFFQTlCNUQ4RTIzNDE5RUIxNjciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUM0QjNBQkEyQUQ2MTFFQTlCNUQ4RTIzNDE5RUIxNjciPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QzRCM0FCNzJBRDYxMUVBOUI1RDhFMjM0MTlFQjE2NyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QzRCM0FCODJBRDYxMUVBOUI1RDhFMjM0MTlFQjE2NyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PtRHfPcAAAAzUExURZWVldfX18PDw62trZubm9zc3Li4uKGhoebm5tLS0uHh4c3Nzaenp729vcjIyLKysuvr6141L40AAAcXSURBVHja7NzZlqpGAEBR5lG0//9rIw7IJKJi4or7PGTdtN10wr5SVAEGf/qqArsAiIAAERAgAgJEQIAIiIAAERAgAgJEQIAIiIAAERAgAgJEQIAIiIAAERAgAgJEQIAIiIAAERAgAgJEQIAIiIAAERAgAgJEQIAIiIAAERAgAgJEQIAIiIAAERAgAgJEQIAIiIAAERAgAgJEQIAIiIAAERAgAgJEQIAICBABERAgAgJEQIAICBABERAgAgJEQIAICBABERAgAgJEQIAICBABERAgAgJEQIAICBABERAgAgJEQIAICBABERAgAgJEQIAICBABERAgAgJEQIAICBABERAgAgJEQIAICBABERAg+nmQFMi5Jis+sIniED23jSzIgLTtg2D//iYme/8QBM/9lQ+CAEhbNLM3N9hEHAThX7GPCiBfAxK1b51kD+R7QMLjXg7iCsgWIPUh7pfVozG791oeBPngm48G583uW5GkBvI+SBaM2xXDn1oqum423bX/mgF5FySc2cv93Voug9TdZotsggnkBZB2NzbhrSY5HnoG07jei8dvzsJB/c3W60SALILE46+WCztsbhPR7R2VJq0ukEcT49nyy8QhaKcRa3fYHZD4+ufqOJAcgDz8/59vtw1I3QP5K6JsOG0vm3hce4I8LQp/BaRZGJC3AAn7IKOKXbC+7EdA5vdmmVwOLksgRThqOqiH4XEGsht+peoPUE8U/jJIO5OLH4GEwUslV5G0PTBG5Uiw/Y2jyigO3l9HAHKv9PYb82LloH74dZBoBUgar+l48NsNvtD0fkez9iwrAvIYZDRCl+Xs149Hm/KZmQ+QjUCiO1ei4ru7EsgnQYrkznlQb7thCuRfAzlOAPN72427P4VA/i2Q/DKT/Ls/VR8fvIBsDZIuz7TPF6TCbnk4GJkB2RokejTjuE7/unlgCuSTIO0Cy+Plp6vDfnQlBchy8QtjSHVd3EgmK1bHLm+H6+nXYbz2DuQRSPnqoL7vvq0u70on4zvxgCyWD3b9UyDVdW24PaWaiGTnFZJwPIQAebDpIKheBIm7n124ZthMJipAlkqHO+IZkP1tbfzOJark/A7MgKyvvl60fRqkvXfhuow+t9+q00+0/yyBrK8ZngOtBzldhw2X9tvpNGty0gvkmbPeJ0Cy/r09s/stbmfo0yMWkEdjevgKyOn2t2pxv7UXoibTdCDLje9/Ww1ymqzn87dbp92242ZmMRjI8hASvwKSLq4udqN6ksw8nxXN3tszD9L8Gkg+2mFrQYql5az4tvFj5xOx4VwnSdeBtGdyPwUytxK77pBVlNHdO7OK3rh/eTPUvdutT3fO52tuHMqD4N7llv8pyOQQ//w19YVDfX27+Sfuby9/6nau4pdA8vEdOZuChEH/quHt0Jg+IRJ/5+PrHwKZXfjbDiS73Zo7mu5UkzX7uTsXe0e/7nC3ePf1O69+BUg2XDfZCqSqOu7rGVf8cHBe8zhC2b61dtUHXv0OkGo6ZL4JkpbRYXdUaFevivx2M/1GIOctNh949TtAoumQ+TpIHMX54CJu+8BDd8FkE5BqcZh/59XvAClmTvKfB0nDqIlHo3T70SftyW1eX9dXtgQJqs1f/Q6QaOa/7wmQKtxH8eiGoCRuovODIO3VxOMmruZbHrLyD7z6DSDtGyT7ew1kf9hNn07c986JTovzzem0Id9wUG+Vk/IDr34DSNR7huZJkMFT6vEhqrPx/j5cnlZML8N6/PAzh9Y99Flm5Yde/c9BquDOkvkKkMP58dA4qi9vivE8JOvGz/j8FokfPpr288+pH2ZPOZrLmeGD+7KOh6dqYWJ48ki7yUg0tz0go/fv/LLddfV3sgOLJyaGPY/zrSlh1a36Arkzoue9CyG35ze6E6/dzO2Ga0EGHqdRJIkfn9/8OEjTW8Vq91ZWh39FeehWA7Nu9ft8CpUEk1WWOyDF0OPyEU2Pnzf/bZC0P6IPzmAvu7KauQBVrgKpJ0tG2arHzX8e5Pb3PezNs/PrX+3JMyCLn9XXf37tPFHvt09WfCDDjx+yyn1/p1V11j7GnB/q3leLuVva79S/tzed+db08YpF4uOZtmz/9oXWMq6BCAgQAQEiIEAERECACAgQAQEiIEAERECACAgQAQEiIEAERECACAgQAQEiIEAERECACAgQAQEiIEAERECACAgQAQEiIEAERECACAgQAQEiIEAERECACAgQAQEiIEAERECACAgQAQEiIEAERECACAgQAQEiIEAEBIiACAgQAQEiIEAEBIiACAgQAQEiIEAEBIiACAgQAQEiIEAEBIiACAgQAQEiIEAEBIiACAgQAQEiIEAEBIiACAgQAQEiIEAEBIiACAgQAQEiIEAEBIiACAgQAQEiIEAEBIiACAgQAQEiIEAEBIiAALELvqt/BBgACqVeUBXxcCkAAAAASUVORK5CYII='
|
|||
|
},
|
|||
|
// 加载失败的错误占位图
|
|||
|
errorImg: {
|
|||
|
type: String,
|
|||
|
default: 'data:image/jpeg;base64,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
|
|||
|
},
|
|||
|
// 图片进入可见区域前多少像素前,单位rpx,开始加载图片
|
|||
|
// 负数为图片超出屏幕底部多少像素后触发懒加载,正数为图片顶部距离屏幕底部多少距离时触发(图片还没出现在屏幕上)
|
|||
|
threshold: {
|
|||
|
type: [Number, String],
|
|||
|
default: 100
|
|||
|
},
|
|||
|
// 是否开启过渡效果
|
|||
|
isEffect: {
|
|||
|
type: Boolean,
|
|||
|
default: true
|
|||
|
},
|
|||
|
// 动画过渡时间
|
|||
|
duration: {
|
|||
|
type: [String, Number],
|
|||
|
default: 500
|
|||
|
},
|
|||
|
// 渡效果的速度曲线,各个之间差别不大,因为这是淡入淡出,且时间很短,不是那些变形或者移动的情况,会明显
|
|||
|
// linear|ease|ease-in|ease-out|ease-in-out|cubic-bezier(n,n,n,n);
|
|||
|
effect: {
|
|||
|
type: String,
|
|||
|
default: 'ease-in-out'
|
|||
|
},
|
|||
|
// 图片高度,单位rpx
|
|||
|
height: {
|
|||
|
type: [String, Number],
|
|||
|
default: 450
|
|||
|
},
|
|||
|
// 图片圆角
|
|||
|
borderRadius: {
|
|||
|
type: String,
|
|||
|
default: ''
|
|||
|
}
|
|||
|
},
|
|||
|
computed: {
|
|||
|
thresholdValue() {
|
|||
|
// 先取绝对值,因为threshold可能是负数,最后根据this.threshold是正数或者负数,重新还原
|
|||
|
let threshold = uni.upx2px(Math.abs(this.threshold))
|
|||
|
return this.threshold < 0 ? -threshold : threshold
|
|||
|
},
|
|||
|
lazyLoadItemStyle() {
|
|||
|
let style = {}
|
|||
|
style.opacity = Number(this.opacity)
|
|||
|
if (this.borderRadius) {
|
|||
|
style.borderRadius = this.borderRadius
|
|||
|
}
|
|||
|
// 因为time值需要改变,所以不直接用duration值(不能改变父组件prop传过来的值)
|
|||
|
style.transition = `opacity ${this.time / 1000}s ${this.effect}`
|
|||
|
style.height = this.$tn.string.getLengthUnitValue(this.height)
|
|||
|
return style
|
|||
|
},
|
|||
|
imageStyle() {
|
|||
|
let style = {}
|
|||
|
if (typeof this.height === 'string' && this.height.indexOf('%') === -1) {
|
|||
|
style.height = this.$tn.string.getLengthUnitValue(this.height)
|
|||
|
}
|
|||
|
return style
|
|||
|
}
|
|||
|
},
|
|||
|
watch: {
|
|||
|
show(val) {
|
|||
|
// 如果不开启过渡效果直接返回
|
|||
|
if (!this.effect) return
|
|||
|
this.time = 0
|
|||
|
// 原来opacity为1(不透明,是为了显示占位图),改成0(透明,意味着该元素显示的是背景颜色,默认的白色),再改成1,是为了获得过渡效果
|
|||
|
this.opacity = 0
|
|||
|
setTimeout(() => {
|
|||
|
this.time = this.duration
|
|||
|
this.opacity = 1
|
|||
|
}, 30)
|
|||
|
},
|
|||
|
image(val) {
|
|||
|
// 修改图片后重置部分变量
|
|||
|
if (!val) {
|
|||
|
// 如果传入null或者'',或者undefined,标记为错误状态
|
|||
|
this.error = true
|
|||
|
} else {
|
|||
|
this.init()
|
|||
|
this.error = false
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
data() {
|
|||
|
return {
|
|||
|
elIndex: this.$tn.uuid(),
|
|||
|
// 显示图片
|
|||
|
show: false,
|
|||
|
// 图片透明度
|
|||
|
opacity: 1,
|
|||
|
// 动画时间
|
|||
|
time: this.duration,
|
|||
|
// 懒加载状态
|
|||
|
// loadlazy-懒加载中状态,loading-图片正在加载,loaded-图片加加载完成
|
|||
|
loadStatus: '',
|
|||
|
// 图片加载失败
|
|||
|
error: false
|
|||
|
}
|
|||
|
},
|
|||
|
created() {
|
|||
|
// 由于一些特殊原因,不能将此变量放到data中定义
|
|||
|
this.observer = {}
|
|||
|
this.observerName = 'lazyLoadContentObserver'
|
|||
|
},
|
|||
|
mounted() {
|
|||
|
// 在需要用到懒加载的页面,在触发底部的时候触发tOnLazyLoadReachBottom事件,保证所有图片进行加载
|
|||
|
this.$nextTick(() => {
|
|||
|
uni.$once('tOnLazyLoadReachBottom', () => {
|
|||
|
if (!this.show) this.show = true
|
|||
|
})
|
|||
|
})
|
|||
|
// mounted的时候,不一定挂载了这个元素,延时30ms,否则会报错或者不报错,但是也没有效果
|
|||
|
setTimeout(() => {
|
|||
|
this.disconnectObserver(this.observerName)
|
|||
|
const contentObserver = uni.createIntersectionObserver(this)
|
|||
|
contentObserver.relativeToViewport({
|
|||
|
bottom: this.thresholdValue
|
|||
|
}).observe(`.tn-lazy-load__item--${this.elIndex}`, (res) => {
|
|||
|
if (res.intersectionRatio > 0) {
|
|||
|
// 懒加载状态改变
|
|||
|
this.show = true
|
|||
|
// 如果图片已经加载,去掉监听,减少性能消耗
|
|||
|
this.disconnectObserver(this.observerName)
|
|||
|
}
|
|||
|
})
|
|||
|
this[this.observerName] = contentObserver
|
|||
|
}, 50)
|
|||
|
},
|
|||
|
methods: {
|
|||
|
// 初始化
|
|||
|
init() {
|
|||
|
this.error = false
|
|||
|
this.loadStatus = ''
|
|||
|
},
|
|||
|
// 处理图片点击事件
|
|||
|
handleImgClick() {
|
|||
|
let whichImg = ''
|
|||
|
// 如果show为false,则表示图片还没有开始加载,点击的是最开始占位图
|
|||
|
if (this.show === false) whichImg = 'lazyImg'
|
|||
|
// 如果error为true,则表示图片加载失败,点击的是错误占位图
|
|||
|
else if (this.error === true) whichImg = 'errorImg'
|
|||
|
// 点击了正常的图片
|
|||
|
else whichImg = 'realImg'
|
|||
|
|
|||
|
this.$emit('click', {
|
|||
|
index: this.index,
|
|||
|
whichImg: whichImg
|
|||
|
})
|
|||
|
},
|
|||
|
// 处理图片加载完成事件,通过show来区分是占位图触发还是加载真正的图片触发
|
|||
|
handleImgLoaded() {
|
|||
|
if (this.loadStatus = '') {
|
|||
|
// 占位图加载完成
|
|||
|
this.loadStatus = 'lazyed'
|
|||
|
}
|
|||
|
else if (this.loadStatus == 'lazyed') {
|
|||
|
// 真正的图片加载完成
|
|||
|
this.loadStatus = 'loaded'
|
|||
|
this.$emit('loaded', this.index)
|
|||
|
}
|
|||
|
},
|
|||
|
// 处理错误图片加载完成
|
|||
|
handleErrorImgLoaded() {
|
|||
|
this.$emit('error', this.index)
|
|||
|
},
|
|||
|
// 处理图片加载失败
|
|||
|
handleImgError() {
|
|||
|
this.error = true
|
|||
|
},
|
|||
|
disconnectObserver(observerName) {
|
|||
|
const observer = this[observerName]
|
|||
|
observer && observer.disconnect()
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
</script>
|
|||
|
|
|||
|
<style lang="scss" scoped>
|
|||
|
.tn-lazy-load {
|
|||
|
&__item {
|
|||
|
background-color: $tn-bg-gray-color;
|
|||
|
overflow: hidden;
|
|||
|
|
|||
|
&__image {
|
|||
|
// 解决父容器会多出3px的问题
|
|||
|
display: block;
|
|||
|
width: 100%;
|
|||
|
// 骗系统开启硬件加速
|
|||
|
transform: transition3d(0, 0, 0);
|
|||
|
// 防止图片加载“闪一下”
|
|||
|
will-change: transform;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
</style>
|