uniapp使用IntersectionObserver实现APP端图片懒加载

2023-03-29 21:39:56    技术分享   

由于UNIAPP中 image 懒加载不能兼容H5和APP端,H5可以通过 vue-lazyload 来实现,APP 图片懒加载一直没有特别好的方案。

APP端可以 使用如下代码可以监听页面Dom元素是否加载

const observer = uni.createIntersectionObserver(this);
observer.relativeToViewport().observe('#' + this.uid, res => {
    if (res.boundingClientRect.top < this.SystemConfig.Height) {
        // 图片可以显示了
        observer.disconnect()
    }
})


完整的VUE组件如下。

<template>
    <view>
        <view :class="classList" :style="styleList" :id="uid">
            <!-- #ifdef MP-WEIXIN -->
            <image lazy-load="true" fade-show
                   :mode="contain?'aspectFit':'aspectFill'"
                   :src="src"/>
            <!-- #endif -->
            <!-- #ifdef H5 -->
            <img v-lazy="src"
                 :style="{objectFit:contain?'contain':'cover'}"/>
            <!-- #endif -->
            <!-- #ifdef APP-PLUS -->
            <image v-if="imageShow"
                   class="image" fade-show
                   :mode="contain?'aspectFit':'aspectFill'"
                   :src="src"/>
            <view v-else></view>
            <!-- #endif -->
        </view>
    </view>
</template>

<script>

let ID_NUMBER = 0;
export default {
    name: "c-cover",
    props: {
        src: {
            type: String,
            default: ''
        },
        ratio: {
            type: String,
            default: '1-1'
        },
        contain: {
            type: Boolean,
            default: false
        },
        borderRadius: {
            type: String,
            default: '0'
        }
    },
    data() {
        return {
            timer: null,
            uid: '',
            imageShow: false,
        }
    },
    created() {
        this.uid = 'CCover' + (ID_NUMBER++)
    },
    mounted() {
        // #ifdef APP-PLUS
        const observer = uni.createIntersectionObserver(this);
        observer.relativeToViewport().observe('#' + this.uid, res => {
            if (this.imageShow) {
                return
            }
            if (res.boundingClientRect.top < this.SystemConfig.Height) {
                this.imageShow = true
                observer.disconnect()
            }
        })
        // #endif
    },
    computed: {
        classList() {
            let classList = ['ratio-' + this.ratio]
            if (this.contain) {
                classList.push('contain')
            }
            return classList
        },
        styleList() {
            let styleList = {}
            if (this.borderRadius) {
                styleList.borderRadius = this.borderRadius
            }
            return styleList
        }
    },
}
</script>

<style scoped>
.pb-cover {
    position: relative;
    overflow: hidden;

    &:after {
        content: '';
        display: block;
        padding-bottom: 100%;
    }

    &.contain {
        .image {
            object-fit: contain;
        }
    }

    &.ratio-1-1 {
        &:after {
            padding-bottom: 100%;
        }
    }

    .image, .image-holder {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
    }

    .image-holder {
        background-color: #FFFFFF;
    }
}
</style>
QQ
微信