guangchao.xu | 070005a | 2020-12-07 09:56:40 +0800 | [diff] [blame^] | 1 | <template> |
| 2 | <view class="u-wrap" :style="{ |
| 3 | opacity: Number(opacity), |
| 4 | borderRadius: borderRadius + 'rpx', |
| 5 | // 因为time值需要改变,所以不直接用duration值(不能改变父组件prop传过来的值) |
| 6 | transition: `opacity ${time / 1000}s ease-in-out` |
| 7 | }" |
| 8 | :class="'u-lazy-item-' + elIndex"> |
| 9 | <view :class="'u-lazy-item-' + elIndex"> |
| 10 | <image :style="{borderRadius: borderRadius + 'rpx', height: imgHeight}" v-if="!isError" class="u-lazy-item" |
| 11 | :src="isShow ? image : loadingImg" :mode="imgMode" @load="imgLoaded" @error="loadError" @tap="clickImg"></image> |
| 12 | <image :style="{borderRadius: borderRadius + 'rpx', height: imgHeight}" class="u-lazy-item error" v-else :src="errorImg" |
| 13 | :mode="imgMode" @load="errorImgLoaded" @tap="clickImg"></image> |
| 14 | </view> |
| 15 | </view> |
| 16 | </template> |
| 17 | |
| 18 | <script> |
| 19 | /** |
| 20 | * lazyLoad 懒加载 |
| 21 | * @description 懒加载使用的场景为:页面有很多图片时,APP会同时加载所有的图片,导致页面卡顿,各个位置的图片出现前后不一致等. |
| 22 | * @tutorial https://www.uviewui.com/components/lazyLoad.html |
| 23 | * @property {String Number} index 用户自定义值,在事件触发时回调,用以区分是哪个图片 |
| 24 | * @property {String} image 图片路径 |
| 25 | * @property {String} loading-img 预加载时的占位图 |
| 26 | * @property {String} error-img 图片加载出错时的占位图 |
| 27 | * @property {String} threshold 触发加载时的位置,见上方说明,单位 rpx(默认300) |
| 28 | * @property {String Number} duration 图片加载成功时,淡入淡出时间,单位ms(默认) |
| 29 | * @property {String} effect 图片加载成功时,淡入淡出的css动画效果(默认ease-in-out) |
| 30 | * @property {Boolean} is-effect 图片加载成功时,是否启用淡入淡出效果(默认true) |
| 31 | * @property {String Number} border-radius 图片圆角值,单位rpx(默认0) |
| 32 | * @property {String Number} height 图片高度,注意:实际高度可能受img-mode参数影响(默认450) |
| 33 | * @property {String Number} mg-mode 图片的裁剪模式,详见image组件裁剪模式(默认widthFix) |
| 34 | * @event {Function} click 点击图片时触发 |
| 35 | * @event {Function} load 图片加载成功时触发 |
| 36 | * @event {Function} error 图片加载失败时触发 |
| 37 | * @example <u-lazy-load :image="image" :loading-img="loadingImg" :error-img="errorImg"></u-lazy-load> |
| 38 | */ |
| 39 | export default { |
| 40 | name: 'u-lazy-load', |
| 41 | props: { |
| 42 | index: { |
| 43 | type: [Number, String] |
| 44 | }, |
| 45 | // 要显示的图片 |
| 46 | image: { |
| 47 | type: String, |
| 48 | default: '' |
| 49 | }, |
| 50 | // 图片裁剪模式 |
| 51 | imgMode: { |
| 52 | type: String, |
| 53 | default: 'widthFix' |
| 54 | }, |
| 55 | // 占位图片路径 |
| 56 | loadingImg: { |
| 57 | type: String, |
| 58 | 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=' |
| 59 | }, |
| 60 | // 加载失败的错误占位图 |
| 61 | errorImg: { |
| 62 | type: String, |
| 63 | default: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQCAMAAAC3Ycb+AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODdDMjhENDYyQUQ2MTFFQTlDQ0VBODgxQjFFOEEyMEMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODdDMjhENDcyQUQ2MTFFQTlDQ0VBODgxQjFFOEEyMEMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4N0MyOEQ0NDJBRDYxMUVBOUNDRUE4ODFCMUU4QTIwQyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4N0MyOEQ0NTJBRDYxMUVBOUNDRUE4ODFCMUU4QTIwQyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PhLwhikAAAAzUExURZWVldfX162t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' |
| 64 | }, |
| 65 | // 图片进入可见区域前多少像素时,单位rpx,开始加载图片 |
| 66 | // 负数为图片超出屏幕底部多少距离后触发懒加载,正数为图片顶部距离屏幕底部多少距离时触发(图片还没出现在屏幕上) |
| 67 | threshold: { |
| 68 | type: [Number, String], |
| 69 | default: 100 |
| 70 | }, |
| 71 | // 淡入淡出动画的过渡时间 |
| 72 | duration: { |
| 73 | type: [Number, String], |
| 74 | default: 500 |
| 75 | }, |
| 76 | // 渡效果的速度曲线,各个之间差别不大,因为这是淡入淡出,且时间很短,不是那些变形或者移动的情况,会明显 |
| 77 | // linear|ease|ease-in|ease-out|ease-in-out|cubic-bezier(n,n,n,n); |
| 78 | effect: { |
| 79 | type: String, |
| 80 | default: 'ease-in-out' |
| 81 | }, |
| 82 | // 是否使用过渡效果 |
| 83 | isEffect: { |
| 84 | type: Boolean, |
| 85 | default: true |
| 86 | }, |
| 87 | // 圆角值 |
| 88 | borderRadius: { |
| 89 | type: [Number, String], |
| 90 | default: 0 |
| 91 | }, |
| 92 | // 图片高度,单位rpx |
| 93 | height: { |
| 94 | type: [Number, String], |
| 95 | default: '450' |
| 96 | } |
| 97 | }, |
| 98 | data() { |
| 99 | return { |
| 100 | isShow: false, |
| 101 | opacity: 1, |
| 102 | time: this.duration, |
| 103 | loadStatus: '', // 默认是懒加载中的状态 |
| 104 | isError: false, // 图片加载失败 |
| 105 | elIndex: this.$u.guid() |
| 106 | } |
| 107 | }, |
| 108 | computed: { |
| 109 | // 将threshold从rpx转为px |
| 110 | getThreshold() { |
| 111 | // 先取绝对值,因为threshold可能是负数,最后根据this.threshold是正数或者负数,重新还原 |
| 112 | let thresholdPx = uni.upx2px(Math.abs(this.threshold)); |
| 113 | return this.threshold < 0 ? -thresholdPx : thresholdPx; |
| 114 | }, |
| 115 | // 计算图片的高度,可能为auto,带%,或者直接数值 |
| 116 | imgHeight() { |
| 117 | return this.$u.addUnit(this.height); |
| 118 | } |
| 119 | }, |
| 120 | created() { |
| 121 | // 由于一些特殊原因,不能将此变量放到data中定义 |
| 122 | this.observer = {}; |
| 123 | }, |
| 124 | watch: { |
| 125 | isShow(nVal) { |
| 126 | // 如果是不开启过渡效果,直接返回 |
| 127 | if (!this.isEffect) return; |
| 128 | this.time = 0; |
| 129 | // 原来opacity为1(不透明,是为了显示占位图),改成0(透明,意味着该元素显示的是背景颜色,默认的白色),再改成1,是为了获得过渡效果 |
| 130 | this.opacity = 0; |
| 131 | // 延时30ms,否则在浏览器H5,过渡效果无效 |
| 132 | setTimeout(() => { |
| 133 | this.time = this.duration; |
| 134 | this.opacity = 1; |
| 135 | }, 30) |
| 136 | }, |
| 137 | // 图片路径发生变化时,需要重新标记一些变量,否则会一直卡在某一个状态,比如isError |
| 138 | image(n) { |
| 139 | if(!n) { |
| 140 | // 如果传入null或者'',或者undefined,标记为错误状态 |
| 141 | this.isError = true; |
| 142 | } else { |
| 143 | this.init(); |
| 144 | this.isError = false; |
| 145 | } |
| 146 | } |
| 147 | }, |
| 148 | methods: { |
| 149 | // 用于重新初始化 |
| 150 | init() { |
| 151 | this.isError = false; |
| 152 | this.loadStatus = ''; |
| 153 | }, |
| 154 | // 点击图片触发的事件,loadlazy-还是懒加载中状态,loading-图片正在加载,loaded-图片加加载完成 |
| 155 | clickImg() { |
| 156 | let whichImg = ''; |
| 157 | // 如果isShow为false,意味着图片还没开始加载,点击的只能是最开始的占位图 |
| 158 | if (this.isShow == false) whichImg = 'lazyImg'; |
| 159 | // 如果isError为true,意味着图片加载失败,这是只剩下错误的占位图,所以点击的只能是错误占位图 |
| 160 | // 当然,也可以给错误的占位图元素绑定点击事件,看你喜欢~ |
| 161 | else if (this.isError == true) whichImg = 'errorImg'; |
| 162 | // 总共三张图片,除了两个占位图,剩下的只能是正常的那张图片了 |
| 163 | else whichImg = 'realImg'; |
| 164 | // 只通知当前图片的index |
| 165 | this.$emit('click', this.index); |
| 166 | }, |
| 167 | // 图片加载完成事件,可能是加载占位图时触发,也可能是加载真正的图片完成时触发,通过isShow区分 |
| 168 | imgLoaded() { |
| 169 | // 占位图加载完成 |
| 170 | if (this.loadStatus == '') { |
| 171 | this.loadStatus = 'lazyed'; |
| 172 | } |
| 173 | // 真正的图片加载完成 |
| 174 | else if (this.loadStatus == 'lazyed') { |
| 175 | this.loadStatus = 'loaded'; |
| 176 | this.$emit('load', this.index); |
| 177 | } |
| 178 | }, |
| 179 | // 错误的图片加载完成 |
| 180 | errorImgLoaded() { |
| 181 | this.$emit('error', this.index); |
| 182 | }, |
| 183 | // 图片加载失败 |
| 184 | loadError() { |
| 185 | this.isError = true; |
| 186 | }, |
| 187 | disconnectObserver(observerName) { |
| 188 | const observer = this[observerName]; |
| 189 | observer && observer.disconnect(); |
| 190 | }, |
| 191 | }, |
| 192 | beforeDestroy() { |
| 193 | // 销毁页面时,可能还没触发某张很底部的懒加载图片,所以把这个事件给去掉 |
| 194 | //observer.disconnect(); |
| 195 | }, |
| 196 | mounted() { |
| 197 | // 此uOnReachBottom事件由mixin.js发出,目的是让页面到底时,保证所有图片都进行加载,做到绝对稳定且可靠 |
| 198 | this.$nextTick(() => { |
| 199 | uni.$once('uOnReachBottom', () => { |
| 200 | if (!this.isShow) this.isShow = true; |
| 201 | }); |
| 202 | }) |
| 203 | // mounted的时候,不一定挂载了这个元素,延时30ms,否则会报错或者不报错,但是也没有效果 |
| 204 | setTimeout(() => { |
| 205 | // 这里是组件内获取布局状态,不能用uni.createIntersectionObserver,而必须用this.createIntersectionObserver |
| 206 | this.disconnectObserver('contentObserver'); |
| 207 | const contentObserver = uni.createIntersectionObserver(this); |
| 208 | // 要理解这里怎么计算的,请看这个: |
| 209 | // https://blog.csdn.net/qq_25324335/article/details/83687695 |
| 210 | contentObserver.relativeToViewport({ |
| 211 | bottom: this.getThreshold, |
| 212 | }).observe('.u-lazy-item-' + this.elIndex, (res) => { |
| 213 | if (res.intersectionRatio > 0) { |
| 214 | // 懒加载状态改变 |
| 215 | this.isShow = true; |
| 216 | // 如果图片已经加载,去掉监听,减少性能的消耗 |
| 217 | this.disconnectObserver('contentObserver'); |
| 218 | } |
| 219 | }) |
| 220 | this.contentObserver = contentObserver; |
| 221 | }, 30) |
| 222 | } |
| 223 | } |
| 224 | </script> |
| 225 | |
| 226 | <style scoped lang="scss"> |
| 227 | @import "../../libs/css/style.components.scss"; |
| 228 | |
| 229 | .u-wrap { |
| 230 | background-color: #eee; |
| 231 | overflow: hidden; |
| 232 | } |
| 233 | |
| 234 | .u-lazy-item { |
| 235 | width: 100%; |
| 236 | // 骗系统开启硬件加速 |
| 237 | transform: transition3d(0, 0, 0); |
| 238 | // 防止图片加载“闪一下” |
| 239 | will-change: transform; |
| 240 | /* #ifndef APP-NVUE */ |
| 241 | display: block; |
| 242 | /* #endif */ |
| 243 | } |
| 244 | </style> |