008-如何判断一个元素是否在可视区域中

实现方式

判断一个元素是否在可视区域内,我们一般使用以下几种方法:

  • offsetTop、scrollTop
  • getBoundingClientRect
  • Intersection Observer

offsetTop、scrollTop

  • offsetTop:返回当前元素的外边框至父元素的上内边框的像素距离
  • scrollTop:一个元素的 scrollTop 值是这个元素的内容顶部(卷起来的)到它的视口可见内容(的顶部)的距离的度量。当一个元素的内容没有产生垂直方向的滚动条,那么它的 scrollTop 值为 0

再了解下以下几个方法:

  • clientWidth:元素内容区宽度加左右内边距宽度,即 content + padding
  • clientHeight:元素内容区高度加上下内边距宽度,即 content + padding
  • scrollWidth:是一个元素内容宽度的度量,包括由于 overflow 溢出而在屏幕上不可见的内容
  • scrollHeight:是一个元素内容高度的度量,包括由于溢出导致的视图中不可见内容

计算公式如下:

// 满足下面判断就在可视区域内
el.offsetTop - document.documentElement.scrollTop <= viewHeight

function viewHeight() {
    // 兼容性写法
    return window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
}

getBoundingClientRect

getBoundingClientRect() 方法返回一个 DOMRect 对象,其提供了元素的大小及其相对于视口的位置。

返回值是一个 DOMRect 对象,是包含整个元素的最小矩形(包括 paddingborder-width)。该对象使用 lefttoprightbottomxywidthheight 这几个以像素为单位的只读属性描述整个矩形的位置和大小。除了 widthheight 以外的属性是相对于视图窗口的左上角来计算的。

如下图说明:

图片1

因此判断一个元素是否在可视区域内,需要满足以下条件:

  • top >= 0
  • left >= 0
  • bottom <= viewHeight
  • right <= viewWidth

实现代码如下:

function isInViewPort(element) {
    const target = document.querySelector('div')
    const viewWidth = window.innerWidth ||
        document.documentElement.clientWidth ||
        document.body.clientWidth
    const viewHeight = window.innerHeight ||
        document.documentElement.clientHeight ||
        document.body.clientHeight
    const {
        top,
        right,
        bottom,
        left,
    } = target.getBoundingClientRect()

  return (
    top >= 0 &&
    left >= 0 &&
    right <= viewWidth &&
    bottom <= viewHeight
  )
}

IntersectionObserver

IntersectionObserver() 构造器创建并返回一个 IntersectionObserver 对象。 如果指定 rootMargin 则会检查其是否符合语法规定,检查阈值以确保全部在 0.01.0 之间,并且阈值列表会按升序排列。如果阈值列表为空,则默认为一个 [0.0] 的数组。

语法如下:

var observer = new IntersectionObserver(callback[, options])

var callback = function (entries, observer) {}

var options = {
    root: document.querySelector('#id'),
    rootMargin: '0px 0px 0px 0px',
    threshold: 1.0,
}

通过 new IntersectionObserver 创建了观察者 observer,传入的参数 callback 在重叠比例超过 threshold 时会被执行。

举个例子:

const target = document.querySelector('.target')
observer.observe(target)

应用场景

  • 列表无限滚动
  • 图片懒加载
  • 可点击链接的预加载
  • 计算广告元素的曝光情况

部分答案整理自网络资源