# 判断元素是否在可视区域内
可视区域即我们浏览网页的设备肉眼可见的区域. 常见的应用场景有:
- 图片的懒加载
 - 列表的无线滚动
 - 计算广告元素的曝光情况
 - 可点击链接的预加载
 
实现的方式常见的有三种:
# Element.getBoundingClientRect()
getBoundingClientRect返回一个DOMRect(opens new window) 对象, 提供了元素的大小及其想对视口的位置.
示意图如下:

如果一个元素在视窗之内的话,那么它一定满足下面四个条件:
- top 大于等于 0
 - left 大于等于 0
 - bottom 小于等于视窗高
 - right 小于等于视窗宽度
 
点击查看代码
/**
 * 判断元素是否在可视区域内 (getBoundingClientRect) 
 * 如果一个元素在视窗之内的话,那么它一定满足下面四个条件:
 * - top 大于等于 
 * - left 大于等于 
 * - bottom 小于等于视窗高
 * - right 小于等于视窗宽度
 * 
 * @param {HTMLElement} element 
 * @returns {boolean}
 */
function inViewport(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
  )
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# IntersctionObserver
Intersection Observer API 会注册一个回调函数, 每当被监视的元素进入或者退出另外一个元素时 (或者 viewport),或者两个元素的相交部分大小发生变化时, 该回调方法会被触发执行
点击查看代码
/**
 * 判断元素是否在可视区域内(IntersectionObserver)
 * MDN: https://developer.mozilla.org/zh-CN/docs/Web/API/IntersectionObserver
 * @param {HTMLElement} element
 */
function inViewport(element) {
  const observeCallback = (entries) => {
    if(entries[0].isIntersecting) {
      console.log('Yes, in viewport.')
    } else {
      console.log('No, not in viewport.')
    }
  }
  const observer = new IntersectionObserver(observeCallback, { threshold: 1.0 })
  observer.observe(element)
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# offsetTop/scrollTop
这种方式受布局影响, 有些不太准确
点击查看代码
/**
 * 判断元素是否在可视区域内(offsetTop scrollTop)
 * 不太准确, 受布局的影响会导致判断偏差
 * 公式: el.offsetTop - document.documentElement.scrollTop <= viewPortHeight
 * @param {HTMLElement} element 
 */
function inViewport(element) {
  const viewportHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
  const elOffsetTop = element.offsetTop
  const docScrollTop = document.documentElement.scrollTop
  const top = elOffsetTop - docScrollTop
  return top <= viewportHeight
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13