自研组件-createIntersectionObserver实现图片懒加载组件

项目:taro3+vue3

描述:图片懒加载通过滚动距离的计算进行加载,这里记录下用createIntersectionObserver来实现
createIntersectionObserver介绍任意门

原理比较简单,通过监听图片,出现在显示区域内就渲染图片,透明度0,图片加载完成后透明度为1,这样就有个过度效果,加载失败显示一个失败的,也可以再加个图片loading的效果,这里直接在容器上设置的背景色代替了

<view
   class="base-lazy-image"
   :id="`base-lazy-image-${index}`">
   <image
     v-if="isShowImg"
     class="img"
     :class="{'active': !isOpacity}"
     :src="url"
     @load="onLoad"
     @error="onError"></image>
   <view
     v-if="isShowError"
     class="error">error</view>
 </view>
.base-lazy-image {
  position: relative;
  width: 200px;
  height: 200px;
  background: red;
  .img {
    width: 100%;
    height: 100%;
    opacity: 0;
    transition: opacity .5s;
    &.active {
      opacity: 1;
    }
  }
  .error {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 10;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    background-color: #f7f8fa;
    color: #969799;
  }
}

isShowImg = ref(false)

isOpacity = ref(true)

isShowError = ref(false)

observer = ref(null)

// 参数
props: {
  url: {
    type: String,
    default: ''
  },
  index: {
    type: Number,
    default: 0
  }
}

clear() {
  if (this.observer.value) {
    this.observer.value.disconnect()
  }
  this.observer.value = null
}

addObserver() {
  let a = getCurrentInstance()
  if (this.observer.value || this.isShowImg.value) {
    return
  }
  const observer = Taro.createIntersectionObserver(a.page)
  observer.relativeToViewport({ bottom: -10 })
    .observe('#base-lazy-image-'+this.props.index, (res) => {
      if (res.intersectionRatio > 0) {
          this.isShowImg.value = true
          this.clear()
        }
    })
  this.observer.value = observer
}

watch(() => props.url, newVal => {
  if (newVal) {
    this.addObserver()
  }
})

页面中使用:

<block v-for="(item, index) in fieldList">
 <view
   :id="`merchant-item-${index}`"
   class="merchant-item f-l-c">
   <base-lazy-image
     :index="index"
     :url="item.url"/>
   <view class="con">
     <view class="name">
       名称-{{ index }}
     </view>
   </view>
 </view>
</block>
async getList() {
    // 获取列表
    const list = await xxx.xxxx()
    this.fieldList.value = list
    setTimeout(() => {
      for(let i = 0; i < this.fieldList.value.length; i++) {
        this.fieldList.value[i].url = this.fieldList.value[i].homeImage
      }
    }, 1000)
  }

注意点:
1、获取列表后要加个延时,要不然监听不到
2、组件里面是通过watch url去添加监听器,这个url必须有个赋值的过程,如果接口里面本来就是有url字段的,组件里面并不会去添加监听器
3、组件内监听的是id, 用index区分,监听到了结果后要断开监听,之前有试过监听 ‘.base-lazy-image’, 会全部展示出来
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Misha韩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值