# getBoundingClientRect

该方法的返回值是一个 DOMRect 对象,这个对象是由该元素的 getClientRects() 方法返回的一组矩形的集合, 即:是与该元素相关的 CSS 边框集合 。

DOMRect 对象包含了一组用于描述边框的只读属性——left、top、right 和 bottom,单位为像素。除了 width 和 height 外的属性都是相对于视口的左上角位置而言的。

注意 left、top、right 和 bottom,它们对应到元素上是这样的:

从图上可以看出 top 属性表示了元素距离可视区域顶部的高度。

下面我们来实现 lazyload 。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .img {
      height: 200px;
      margin-bottom: 20px;
      background-color: gray;
    }

    .pic {
      width: 100%;
      height: 100%;
    }
    span {
      color: red;
    }
  </style>
</head>

<body>
  <div class="container">
    <span>1</span>
    <div class="img">
      <!-- 注意我们并没有为它引入真实的src -->
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
    <span>2</span>
    <div class="img">
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
    <span>3</span>
    <div class="img">
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
    <span>4</span>
    <div class="img">
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
    <span>5</span>
    <div class="img">
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
    <span>6</span>
    <div class="img">
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
    <span>7</span>
    <div class="img">
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
    <span>8</span>
    <div class="img">
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
    <span>9</span>
    <div class="img">
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
    <span>10</span>
    <div class="img">
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
  </div>
  <script>
    const imgs = document.getElementsByTagName('img');
    const viewHeight = window.innerHeight || document.documentElement.clientHeight;

    let num = 0;
    function lazyLoad() {
      for (let i = num, len = imgs.length; i < len; i++) {
        const distance = viewHeight - imgs[i].getBoundingClientRect().top;
        
        if (distance >= 0) {
          imgs[i].src = imgs[i].getAttribute('data-src');
          num = i + 1;
        }
      }
    }
    lazyLoad()
    window.addEventListener('scroll', lazyLoad, false)
  </script>
</body>

</html>

# offsetHeight、scrollTop

在开始之前我们先来看下 offsetHeight、scrollTop 等,看看它们具体指的是哪一块。

offsetTop, offsetLeft:只读属性。要确定的这两个属性的值,首先得确定元素的offsetParent。offsetParent指的是距该元素最近的position不为static的祖先元素,如果没有则指向body元素。确定了offsetParent,offsetLeft指的是元素左侧偏移offsetParent的距离,同理offsetTop指的是上侧偏移的距离。

offsetHeight, offsetWidth:只读属性。这两个属性返回的是元素的高度或宽度,包括元素的边框、内边距和滚动条。返回值是一个经过四舍五入的整数。如下图:

scrollHeight, scrollWidth:只读属性。返回元素内容的整体尺寸,包括元素看不见的部分(需要滚动才能看见的)。返回值包括padding,但不包括margin和border。如下图:

scrollTop, scrollLeft:图中已经表示的很明白了。如果元素不能被滚动,则为0。

window.innerWidth, window.innerHeight:只读。视口(viewport)的尺寸,包含滚动条

clientHeight, clientWidth:包括padding,但不包括border, margin和滚动条。如下图:

Element.getBoundingClientRect():只读,返回浮点值。这个方法非常有用,常用于确定元素相对于视口的位置。该方法会返回一个DOMRect对象,包含left, top, width, height, bottom, right六个属性:left, right, top, bottom:都是元素(不包括margin)相对于视口的原点(视口的上边界和左边界)的距离。

height, width:元素的整体尺寸,包括被滚动隐藏的部分;padding和border参与计算。另外,heigth=bottom-top, width=right-left。

下面我们来实现图片懒加载。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .img {
      height: 200px;
      margin-bottom: 20px;
      background-color: gray;
    }

    .pic {
      width: 100%;
      height: 100%;
    }
    span {
      color: red;
    }
  </style>
</head>

<body>
  <div class="container">
    <span>1</span>
    <div class="img">
      <!-- 注意我们并没有为它引入真实的src -->
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
    <span>2</span>
    <div class="img">
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
    <span>3</span>
    <div class="img">
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
    <span>4</span>
    <div class="img">
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
    <span>5</span>
    <div class="img">
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
    <span>6</span>
    <div class="img">
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
    <span>7</span>
    <div class="img">
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
    <span>8</span>
    <div class="img">
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
    <span>9</span>
    <div class="img">
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
    <span>10</span>
    <div class="img">
      <img class="pic" alt="加载中" data-src="https://img1.baidu.com/it/u=2260373675,224366072&fm=26&fmt=auto&gp=0.jpg">
    </div>
  </div>
  <script>
    const imgs = document.getElementsByTagName('img');
    const viewHeight = window.innerHeight || document.documentElement.clientHeight;
    const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
    let num = 0;


    function lazyload() {
      for (let i = num, len = imgs.length; i < len; i++) {
        if (imgs[i].offsetHeight <= viewHeight + scrollTop) {
          imgs[i].src = imgs[i].getAttribute('data-src')
        }
      }
    }

    lazyload();

    window.addEventListener('scroll', lazyload, false);
  </script>
</body>

</html>

# 参考文章

一张图彻底掌握 scrollTop, offsetTop, scrollLeft, offsetLeft...... (opens new window)