123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- <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
- },
-
- errorImg: {
- type: String,
- default: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQCAMAAAC3Ycb+AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODdDMjhENDYyQUQ2MTFFQTlDQ0VBODgxQjFFOEEyMEMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODdDMjhENDcyQUQ2MTFFQTlDQ0VBODgxQjFFOEEyMEMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4N0MyOEQ0NDJBRDYxMUVBOUNDRUE4ODFCMUU4QTIwQyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4N0MyOEQ0NTJBRDYxMUVBOUNDRUE4ODFCMUU4QTIwQyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PhLwhikAAAAzUExURZWVldfX162trcPDw5ubm7i4uNzc3Obm5s3NzaGhoeHh4cjIyKenp9LS0r29vbKysuvr67sDMEkAAAlpSURBVHja7NzpYqMgAIVRUVHc8/5PO66R1WAbOzX97q+ZtDEpR0AWTR7kVyWhCAAhgABCAAGEAAIIAQQQAggBBBACCCAEEEAIIIAQQAgggBBAACGAAEIAAYQAQgABhAACCAEEEAIIIAQQAgggBBBACCCAEEAAIYAQQAAhgABCAAGEAAIIAYQAAggBBBACCCAEEEAIIAQQQAgggBBAACGAAEIAIYAAQgABhAACCAEEEAIIAQQQAgggBBBACCCAEEAAIYAQQAAhgABCAAGEAAIIAYQAAggBBBACCCAEEEAIIAQQQAgggBBAACGAAEIAIYAAQgABhAACCAEEEAIIAQQQAgggBBBACCCAEEAIIIAQQAAhgABCAAGEAEIAAYQAAggBBBACCCAEEAIIIAQQQAgggBBAACGAEEAAIYAAsqeX5QWHKIcs/Ptl03lfL4zDFPWfBGmSpPn+IZzSH5KkCL5B+n+oklwz6Iz
- },
-
-
- threshold: {
- type: [Number, String],
- default: 100
- },
-
- isEffect: {
- type: Boolean,
- default: true
- },
-
- duration: {
- type: [String, Number],
- default: 500
- },
-
-
- effect: {
- type: String,
- default: 'ease-in-out'
- },
-
- height: {
- type: [String, Number],
- default: 450
- },
-
- borderRadius: {
- type: String,
- default: ''
- }
- },
- computed: {
- thresholdValue() {
-
- 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
- }
-
- style.transition = `opacity ${this.time / 1000}s ${this.effect}`
- style.height = this.$t.string.getLengthUnitValue(this.height)
- return style
- },
- imageStyle() {
- let style = {}
- if (typeof this.height === 'string' && this.height.indexOf('%') === -1) {
- style.height = this.$t.string.getLengthUnitValue(this.height)
- }
- return style
- }
- },
- watch: {
- show(val) {
-
- if (!this.effect) return
- this.time = 0
-
- this.opacity = 0
- setTimeout(() => {
- this.time = this.duration
- this.opacity = 1
- }, 30)
- },
- image(val) {
-
- if (!val) {
-
- this.error = true
- } else {
- this.init()
- this.error = false
- }
- }
- },
- data() {
- return {
- elIndex: this.$t.uuid(),
-
- show: false,
-
- opacity: 1,
-
- time: this.duration,
-
-
- loadStatus: '',
-
- error: false
- }
- },
- created() {
-
- this.observer = {}
- this.observerName = 'lazyLoadContentObserver'
- },
- mounted() {
-
- this.$nextTick(() => {
- uni.$once('tOnLazyLoadReachBottom', () => {
- if (!this.show) this.show = true
- })
- })
-
- 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 = ''
-
- if (this.show === false) whichImg = 'lazyImg'
-
- else if (this.error === true) whichImg = 'errorImg'
-
- else whichImg = 'realImg'
-
- this.$emit('click', {
- index: this.index,
- whichImg: whichImg
- })
- },
-
- 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 {
-
- display: block;
- width: 100%;
-
- transform: transition3d(0, 0, 0);
-
- will-change: transform;
- }
- }
- }
- </style>
|