美文网首页让前端飞
可视区域图片懒加载如何处理

可视区域图片懒加载如何处理

作者: Skywang | 来源:发表于2022-09-26 14:11 被阅读0次

    一、用途

      在日常开发中,我们经常需要判断目标元素是否在视窗之内或者和视窗的距离小于一个值(例如 100 px),从而实现一些常用的功能,例如:

    • 图片的懒加载

    二、实现方式

    判断一个元素是否在可视区域,我们常用的有三种办法:

    • offsetTop、scrollTop 这种方式有一定局限性 受offsetParenty影响

    • getBoundingClientRect 如果元素很多 性能不如第三种

    • Intersection Observer 顾名思义 重叠观察者(本文先不谈)

    offsetTop、scrollTop

    offsetTop,元素的上外边框至包含元素的上内边框之间的像素距离,其他offset属性如下图所示:

    image.png
    下面再来了解下clientWidthclientHeight
    • clientWidth:元素内容区宽度加上左右内边距宽度,即clientWidth = content + padding
    • clientHeight:元素内容区高度加上上下内边距高度,即clientHeight = content + padding

    这里可以看到client元素都不包括外边距

    最后,关于scroll系列的属性如下:

    • scrollWidthscrollHeight 主要用于确定元素内容的实际大小

    • scrollLeftscrollTop 属性既可以确定元素当前滚动的状态,也可以设置元素的滚动位置

      • 垂直滚动 scrollTop > 0
      • 水平滚动 scrollLeft > 0
    • 将元素的 scrollLeftscrollTop 设置为 0,可以重置元素的滚动位置

    注意

    上述属性都是只读的,每次访问都要重新开始
    有一定局限性 offsetTop元素到最近的一个具有定位的祖宗元素的距离,若祖宗都不符合条件,祖宗为body

    下面再看看如何实现判断:
    公式如下:

    el.offsetTop - document.documentElement.scrollTop <=  window.innerHeight
    

    代码实现:

    function isInViewPortOfOne (el) {
        // viewPortHeight 兼容所有浏览器写法
        const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight 
        const offsetTop = el.offsetTop
        const scrollTop = document.documentElement.scrollTop
        const top = offsetTop - scrollTop
        return top <= viewPortHeight
    }
    

    getBoundingClientRect

    返回值是一个 DOMRect对象,拥有left, top, right, bottom, x, y, width, 和 height属性

    const target = document.querySelector('.target');
    const clientRect = target.getBoundingClientRect();
    console.log(clientRect);
    
    // {
    //   bottom: 556.21875,
    //   height: 393.59375,
    //   left: 333,
    //   right: 1017,
    //   top: 162.625,
    //   width: 684
    // }
    

    属性对应的关系图如下所示:


    image.png

    当页面发生滚动的时候,top与left属性值都会随之改变

    如果一个元素在视窗之内的话,那么它一定满足下面四个条件:

    • top 大于等于 0
    • left 大于等于 0
    • bottom 小于等于视窗高度
    • right 小于等于视窗宽度

    实现代码如下:

    function isInViewPort(element) {
      const viewWidth = window.innerWidth || document.documentElement.clientWidth;
      const viewHeight = window.innerHeight || document.documentElement.clientHeight;
      const {
        top,
        right,
        bottom,
        left,
      } = element.getBoundingClientRect();
    
      return (
        top >= 0 &&
        left >= 0 &&
        right <= viewWidth &&
        bottom <= viewHeight
      );
    }
    

    例子:

    // 列表数据
     // 行
    <div v-for="(row, indexs) in items" :key="indexs" class="rowList" >
      <div v-for="(column, index) in coluData" :key="index" class="coluList">   // 列
        <div class="images">
           <img class="lazyImg" slot="reference" :src="logo" :data-src="row[column.columnName]" alt="" />
        </div>
      </div>
    </div>
    // 在生命周期中定义滚动事件
        mounted() {
          window.addEventListener('scroll', this.lazyload)
        },
        destroyed() {
          window.removeEventListener('scroll', this.lazyload)
        },
        mothods:{
          getListData(){
              this.items = getData // getdata请求到的列表数据
              this.$nextTick(()=>{
                  this.lazyload()
              })
          },
          // 图片懒加载
          lazyload(){
            let n = 0;
            let img = document.getElementsByClassName('lazyImg')
            for(let i = n; i < img.length; i++){
              if(this.isInViewPort(img[i])){     
                img[i].src = img[i].getAttribute("data-src");
                n = i + 1;
              }
            }
          },
          isInViewPort(element) {
            const viewWidth = window.innerWidth || document.documentElement.clientWidth;
            const viewHeight = window.innerHeight || document.documentElement.clientHeight;
            const {
              top,
              right,
              bottom,
              left,
            } = element.getBoundingClientRect();
    
            return (
              top >= 0 &&
              left >= 0 &&
              right <= viewWidth &&
              bottom <= viewHeight
            );
          },
    }
    

    相关文章

      网友评论

        本文标题:可视区域图片懒加载如何处理

        本文链接:https://www.haomeiwen.com/subject/tfiwortx.html