要检测一个元素是否可见或者两个元素是否相交的需求场景有这些:
- 图片懒加载——当图片滚动到可见时才进行加载
- 内容无限滚动——也就是用户滚动到接近内容底部时直接加载更多,而无需用户操作翻页,给用户一种网页可以无限滚动的错觉
- 检测广告的曝光情况——为了计算广告收益,需要知道广告元素的曝光情况
- 在用户看见某个区域时执行任务或播放动画
1. 知识铺垫:确定浏览器窗口的尺寸
有三种方法能够确定浏览器窗口的尺寸(浏览器的视口,不包括工具栏和滚动条)。
对于Internet Explorer、Chrome、Firefox、Opera 以及 Safari:
window.innerHeight - 浏览器窗口的内部高度
window.innerWidth - 浏览器窗口的内部宽度
对于 Internet Explorer 8、7、6、5:
document.documentElement.clientHeight
document.documentElement.clientWidth
或者混杂模式(没有)下:
document.body.clientHeight
document.body.clientWidth
实用的 JavaScript 方案(涵盖所有浏览器):
var w=window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
var h=window.innerHeight
|| document.documentElement.clientHeight
|| document.body.clientHeight;
一些其他 Window 方法:
window.open() - 打开新窗口
window.close() - 关闭当前窗口
window.moveTo() - 移动当前窗口
window.resizeTo() - 调整当前窗口的尺寸
scrollTop()
: 方法设置或返回被选元素的垂直滚动条位置。
当用于返回位置时:
该方法返回第一个匹配元素的滚动条的垂直位置。
当用于设置位置时:
该方法设置所有匹配元素的滚动条的垂直位置。
scrollHeight属性
: 滚动的总高度,指的是包含滚动内容的元素大小(元素内容的总高度)。
window.scrollBy(x,y)
:x轴,y轴的一次滚动的距离。
2. 判断元素是否出现在视口:
方法一:offsetTop - scrollTop <= 视口高度
function isInViewPortOfOne (element) {
// 获取可视窗口的高度。兼容所有浏览器
const screenHeight = window.innerHeight || document.documentElement.clientHeight
|| document.body.clientHeight;
// 获取滚动条滚动的高度
const scrollTop = document.documentElement.scrollTop;
// 获取元素偏移的高度。就是距离可视窗口的偏移量。
const offsetTop = element.offsetTop;
// 加100是为了提前加载
return offsetTop - scrollTop <= screenHeight + 100;
}
方法二:getBoundingClientReact()
getBoundingClientReact()
返回值是一个 DOMRect对象,拥有left, top, right, bottom, x, y, width, height
属性。
公式: el.getBoundingClientReact().top <= viewPortHeight
function isInViewPortOfTwo (el) {
const screenHeight = window.innerHeight || document.documentElement.clientHeight
|| document.body.clientHeight;
const top = el.getBoundingClientRect() && el.getBoundingClientRect().top;
return top <= screenHeight + 100;
}
方法三: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节点
更多 IntersectionObserver
介绍,参见:
- https://juejin.cn
- MDN