前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >图片懒加载组件封装,加载时loading效果,加载失败暂时默认图片

图片懒加载组件封装,加载时loading效果,加载失败暂时默认图片

作者头像
用户10106350
发布2022-10-28 11:26:43
1.3K0
发布2022-10-28 11:26:43
举报
文章被收录于专栏:WflynnWeb

组件代码

代码语言:javascript
复制
<template>
  <view class="easy-loadimage" :id="uid">
    <image class="origin-img" :src="imageSrc" :mode="mode" @click="ui.showImg(imageSrc)"
         v-if="loadImg&&!isLoadError" v-show="showImg"
         :class="{'no-transition':!openTransition,'show-transition':showTransition&&openTransition}"
         @load="handleImgLoad" @error="handleImgError">
    </image>
    <view class="loadfail-img" v-else-if="isLoadError"></view>
    <view :class="['loading-img',loadingMode]" v-show="!showImg&&!isLoadError"></view>
  </view>
</template>
代码语言:javascript
复制
<script>
    // 生成全局唯一id
    function generateUUID() {// eslint-disable-line
        // eslint-disable-next-line
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            const r = Math.random() * 16 | 0 // eslint-disable-line
            const v = c == 'x' ? r : (r & 0x3 | 0x8) // eslint-disable-line
            return v.toString(16) // eslint-disable-line
        })
    }

    export default {
        props: {
            imageSrc: {
                type: String,
            },
            mode: {
                type: String,
            },
            scrollTop: {
                type: Number,
            },
            loadingMode: {
                type: String,
                default: 'looming-gray'
            },
            openTransition: {
                type: Boolean,
                default: true,
            },
            viewHeight: {
                type: Number,
                default() {
                    return uni.getSystemInfoSync().windowHeight
                }
            },
      showAll: { // 是否显示全部图片
          type: Boolean,
          default: true,
          required: false
      },

        },
        watch: {
            scrollTop(val) {
                this.onScroll(val)
            }
        },
        data() {
            return {
                uid: '',
                loadImg: false,
                showImg: false,
                isLoadError: false,
                showTransition: false,
            }
        },
        methods: {
            init() {
                this.uid = 'uid-' + generateUUID()
                this.$nextTick(this.onScroll)
            },
            handleImgLoad(e) {
                this.showImg = true

                setTimeout(() => {
                    this.showTransition = true
                }, 50)
            },
            handleImgError(e) {
                this.isLoadError = true
            },
            onScroll(scrollTop) {
                // 加载ing时才执行滚动监听判断是否可加载
                if (this.loadImg || this.isLoadError) return
                const id = this.uid
                const query = uni.createSelectorQuery().in(this)
                query.select('#' + id).boundingClientRect(data => {
                    if (this.showAll) {
                        this.loadImg = true
                    } else {
                        if (!data) return
                        if (data.top - this.viewHeight < 0) {
                            this.loadImg = true
                        }
          }
                }).exec()
            },
        },
        mounted() {
            this.init()
        }
    }
</script>
代码语言:javascript
复制
<style scoped>
  /* 官方优化图片tips */
  image {
    will-change: transform
  }

  /* 渐变过渡效果处理 */
  image.origin-img {
    opacity: 0.3;
  }

  image.origin-img.show-transition {
    transition: opacity 1.2s;
    opacity: 1;
  }

  image.origin-img.no-transition {
    opacity: 1;
  }

  /* 加载失败、加载中的占位图样式控制 */
  .loadfail-img {
    height: 100%;
    background: url('@/static/images/common/loadfail.png') no-repeat center;
    background-size: 50%;
  }

  .loading-img {
    height: 100%;
  }

  /* 转圈 */
  .spin-circle {
    background: url('@/static/images/common/loading1.gif') no-repeat center;
    background-size: 100 rpx;
  }

  /* 动态灰色若隐若现 */
  .looming-gray {
    animation: looming-gray 1s infinite linear;
    background-color: #e3e3e3;
  }

  @keyframes looming-gray {
    0% {
      background-color: #e3e3e3aa;
    }
    50% {
      background-color: #e3e3e3;
    }
    100% {
      background-color: #e3e3e3aa;
    }
  }

  /* 骨架屏1 */
  .skeleton-1 {
    background-color: #e3e3e3;
    background-image: linear-gradient(100deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0) 80%);
    background-size: 100 rpx 100%;
    background-repeat: repeat-y;
    background-position: 0 0;
    animation: skeleton-1 .6s infinite;
  }

  @keyframes skeleton-1 {
    to {
      background-position: 200% 0;
    }
  }

  /* 骨架屏2 */
  .skeleton-2 {
    background-image: linear-gradient(-90deg, #fefefe 0%, #e6e6e6 50%, #fefefe 100%);
    background-size: 400% 400%;
    background-position: 0 0;
    animation: skeleton-2 1.2s ease-in-out infinite;
  }

  @keyframes skeleton-2 {
    to {
      background-position: -135% 0;
    }
  }
</style>

调用方法示例

代码语言:javascript
复制
<template>
    <view class="list">
        <view class="item" v-for="(item,index) of list" :key="index">
            <imgLoad  mode="widthFix"
                :scroll-top="scrollTop"
                :image-src="item.image"></imgLoad >
            <text>{{item.content}}</text>
        </view>
    </view>
</template>
    export default{
        data(){
            return {
                list:MockData, // 此处放自己的测试数据
                scrollTop:0
            }
        },
        onPageScroll({scrollTop}) {
            // 传入scrollTop值并触发所有easy-loadimage组件下的滚动监听事件
            this.scrollTop = scrollTop;
        },
    }

<style scoped>
    .list{display: flex;justify-content: space-between;flex-wrap: wrap;padding: 32rpx;background: #F1F1F1;}
    .list .item{width: 48%;background: #fff;margin-bottom: 80rpx;border-radius: 20rpx;}
    .list .item >>> .easy-loadimage{
        width: 100%;
        /* height: 500rpx; */
        margin-bottom: 38rpx;
    }
    .list .item >>> .origin-img{
        border-radius: 20rpx;
    }
    /* mode为widthFix即图片高度自适应时要设置占位图默认高度 */
    .list .item >>> .loadfail-img,.list .item >>>.loading-img{
        height: 500rpx;
    }
</style

组件属性

属性名

类型

必填

默认值

说明

image-src

String

图片资源地址

scroll-top

Number

传入滚动值监听并触发组件

mode

String

同image组件的mode属性

loading-mode

String

looming-gray

loading加载中的占位图效果

open-transition

Boolean

true

是否开启加载成功后的渐现过渡效果

view-height

Number

真机可视窗高度

可视区域高度

view-height属性说明

  • 在大量图片在同一个页面使用该组件时可传入可视区域高度,避免重复获取窗口高度
  • 你也可以在页面(父组件)传入比真机可视窗高度更大的值当做阈值提前进入加载

loading属性说明

说明

spin-circle

转圈圈

looming-gray

动态灰背景若隐若现

skeleton-1

骨架屏效果1

skeleton-2

骨架屏效果2

你也可以在以此类推在源码上修改或者扩展为你理想的样式

使用深度作用选择器>>>或在插件源码CSS部分上进行样式修改

类名元素说明

类名

说明

.easy-loadimage

图片父元素

.origin-img

源图片

.loading-img

加载占位图

.loadfail-img

加载失败占位图

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-06-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 WflynnWeb 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 组件属性
    • view-height属性说明
      • loading属性说明
        • 类名元素说明
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档