如何确定这个元素‘你’看得见or看不见

336 阅读1分钟

应用场景

  • 图片懒加载——当图片滚动到可见时才进行加载
  • 内容无限滚动——也就是用户滚动到接近内容底部时直接加载更多,而无需用户操作翻页,给用户一种网页可以无限滚动的错觉
  • 计算广告元素的曝光情况
  • 可点击链接的预加载

#

先理解一下scrollTop offsetTop概念以及区别

  • 有三种方法能够确定浏览器窗口的尺寸(浏览器的视口,不包括工具栏和滚动条)。

scrollTop

scrollTop 可设置或获取位于对象最顶端和窗口中可见内容的最顶端之间的距离。

const scrollTop = element.scrollTop;

scrollTop 可以是任意整数

image.png

offsetTop

DOM 元素的 offsetTop 这是只读属性与 offsetParent 属性有关。要确定这个属性的值,首先得确定元素的 offsetParent。确定了 offsetParent, offsetTop 指的是上侧偏移的距离。

image.png

screenHeight/innerHeight/clientHeigt

clientHeight表示元素内容可视区的宽度和高度,包括边距大小(padding),但是不包括边框(border)和滚动条(scroll bar)。clientWidth 与 offsetWidth 的差别就在于边框与滚动条上。 JavaScript方式确定浏览器窗口的尺寸(浏览器的视口,不包括工具栏和滚动条)

var w=window.innerWidth
	|| document.documentElement.clientWidth
	|| document.body.clientWidth;

var h=window.innerHeight
	|| document.documentElement.clientHeight
	|| document.body.clientHeight;

image.png

如何实现

方法一:offsetTop - scrollTop <= 视口高度

看图即可明白左边计算可以得到元素相对于视口顶部的距离,即元素顶部到视口顶部的距离。这个距离可以用于判断元素是否在视口内或计算元素进入视口的动画效果。

function isInViewPortOfOne (element) {
  // 获取可视窗口的高度,多种方式,可以兼容所有浏览器
  const screenHeight = window.innerHeight || document.documentElement.clientHeight
  	 || document.body.clientHeight;
  // 获取滚动条滚动的高度
  const scrollTop = document.documentElement.scrollTop;
  // 获取元素距离可视窗口的偏移量。
  const offsetTop = element.offsetTop;
  //左边等于元素
  return offsetTop - scrollTop <= screenHeight 
}

image.png

方法二:getBoundingClientRect()

const target = document.querySelector('.target');
const clientRect = target.getBoundingClientRect();
console.log(clientRect);

当页面发生滚动的时候,topleft属性值都会随之改变 image.png

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

  • 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
  );
}

方法三:IntersectionObserver

// io 为 IntersectionObserver对象 - 由IntersectionObserver()构造器创建
 var io = new IntersectionObserver((entries) => {
   // entries 为 IntersectionObserverEntry对象数组
   entries.forEach((item) => {
     // item 为 IntersectionObserverEntry对象
     // isIntersecting是一个Boolean值,判断目标元素当前是否可见
     if (item.isIntersecting) {
       // div 可见时 进行相关操作
       console.log(item.target.innerText);
       io.unobserve(item.target); //停止监听该div DOM节点
     }
   });
 }); // 不传options参数,默认根元素为浏览器视口
const divArr = [...document.querySelectorAll(".item")];
 divArr.forEach((div) => io.observe(div)); // 遍历监听所有div DOM节点