应用场景
- 图片懒加载——当图片滚动到可见时才进行加载
- 内容无限滚动——也就是用户滚动到接近内容底部时直接加载更多,而无需用户操作翻页,给用户一种网页可以无限滚动的错觉
- 计算广告元素的曝光情况
- 可点击链接的预加载
#
先理解一下scrollTop offsetTop概念以及区别
- 有三种方法能够确定浏览器窗口的尺寸(浏览器的视口,不包括工具栏和滚动条)。
scrollTop
scrollTop
可设置或获取位于对象最顶端和窗口中可见内容的最顶端之间的距离。
const scrollTop = element.scrollTop;
scrollTop
可以是任意整数
offsetTop
DOM 元素的 offsetTop
这是只读属性与 offsetParent
属性有关。要确定这个属性的值,首先得确定元素的 offsetParent
。确定了 offsetParent
, offsetTop
指的是上侧偏移的距离。
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;
如何实现
方法一: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
}
方法二:getBoundingClientRect()
const target = document.querySelector('.target');
const clientRect = target.getBoundingClientRect();
console.log(clientRect);
当页面发生滚动的时候,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
);
}
方法三: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节点