uni-app实现图片懒加载教程,基于intersectionObserver的relativeToViewport实现,支持微信小程序和app。先看下效果:
加载中:
加载后:
1、新建lazy-load-image.vue文件,放到组件中:
<template> <view :style="{ width, height }"> <!-- 加载中 --> <image :src="loadSrc" class="lazy-image lazy-load" @load="init" mode="scaleToFill" :style="{ opacity:isShow?'0':'1', borderRadius, width, height, transition: `opacity ${duration/1000}s ${effect}` }"></image> <!-- 加载成功 --> <image @load="load" @error="error" v-if="status==1" :src="src" mode="scaleToFill" :style="{ opacity:isShow?'1':'0', borderRadius, width, height, transition: `opacity ${duration/1000}s ${effect}` }"> </image> <!-- 加载失败 --> <image v-if="status==2" :src="errorSrc" mode="scaleToFill" :style="{ opacity:isShow?'1':'0', borderRadius, width, height, transition: `opacity ${duration/1000}s ${effect}` }"> </image> </view> </template> <script> let loadTimer = null import loadingImage from '../static/loading.png' import loadFailImage from '../static/loadFail.png' /** * 懒加载插件 * @description 懒加载插件 * * @property {String} borderRadius 图片圆角,必须带尺寸单位 * @property {String} width 图片宽度,必须带尺寸单位(默认100%) * @property {String} height 图片高度,必须带尺寸单位(默认100%) * @property {String} src 图片链接,不传的话会一直是加载中状态 * @property {String|Number} minTimeOut 当图片加载过快(存在缓存)至少显示多少秒加载动画 * @property {String} effect = [linear|ease|ease-in|ease-out|ease-in-out] 过渡效果,可以用cubic-bezier * @value linear 规定以相同速度开始至结束的过渡效果(默认) * @value ease 规定慢速开始,然后变快,然后慢速结束的过渡效果 * @value ease-in 规定以慢速开始的过渡效果 * @value ease-out 规定以慢速结束的过渡效果 * @value ease-in-out 规定以慢速开始和结束的过渡效果 * @property {String|Number} duration 图片加载成功后的过渡时间,单位毫秒 * @property {Object} showDistance 当图片到屏幕哪个位置的时候开始加载,单位px,可以是负数 (默认{bottom:0}) * @property {String} loadSrc 加载中显示的图片,输入网络路径或绝对路径 * @property {String} errorSrc 加载失败显示的图片,输入网络路径或绝对路径 * @event {Function} show 当图片进入页面触发 * @event {Function} showSuccess 当图片完全加载完毕触发 * @example <lazy-load-image :src="src" width="100rpx" height="100rpx"></lazy-load-image> */ export default { name: "lazy-load-image", props: { //图片圆角 必须带尺寸单位 borderRadius: { type: String, default: '0' }, //图片宽度 width: { type: String, default: '100%' }, height: { type: String, default: '100%' }, //图片链接 src: { type: String, default: '' }, //当图片加载过快(存在缓存)至少显示多少秒加载动画 minTimeOut: { type: String || Number, default: '300' }, //当图片到屏幕哪个位置的时候开始加载 单位px 可以是负数 showDistance: { type: Object, default: () => { bottom: 20 } }, //过渡效果 linear / ease / ease-in / ease-out / ease-in-out effect: { type: String, default: 'linear' }, //图片加载成功后的过渡时间 单位毫秒 duration: { type: String || Number, default: '300' }, //加载中图片 loadSrc: { type: String, default: loadingImage }, //加载失败图片 errorSrc: { type: String, default:loadFailImage } }, data() { return { status: 0, //0加载中 1加载成功 2加载失败 isShow: false } }, watch: { //当链接变化重新加载 src() { if (!this.isShow) return this.status = 0 this.isShow = false this.$nextTick(() => { this.status = 1 }) } }, destroyed() { //页面销毁取消监听 this.$emit('destroyed') }, methods: { load() { if (this.minTimeOut == 0) { this.isShow = true }else{ let newTimer = new Date().getTime() - loadTimer if (newTimer < this.minTimeOut) { setTimeout(() => { this.isShow = true }, this.minTimeOut - newTimer) } else { this.isShow = true } } setTimeout(()=>{ this.$emit('showSuccess'); },this.duration) }, error() { this.status = 2 this.isShow = true }, init(){ let intersectionObserver = uni.createIntersectionObserver(this) let load = false //当图片加载完的时候取消监听 this.$once('destroyed', () => { intersectionObserver.disconnect() }) intersectionObserver.relativeToViewport(this.showDistance).observe('.lazy-load', (res) => { if (!load && res.intersectionRatio == 0) { load = true return } this.$emit('show'); load = true this.status = 1 loadTimer = new Date().getTime() intersectionObserver.disconnect() }) } } } </script> <style scoped> .lazy-content { overflow: hidden; position: relative; .lazy-image { display: block; will-change: transform; } .lazy-load { position: absolute; left: 0; top: 0; } } </style>
2、在需要使用懒加载的页面引入插件:
import lazyLoadImage from '../../components/lazyLoadImage.vue' export default { components: {lazyLoadImage}, }
3、替换原来的图片为插件,宽度和src一定要传,更多参数见代码中的注释:
<lazy-load-image :src="$app.imgUrl + item.coverImage" width="345rpx" height="345rpx"></lazy-load-image>