【前端】如何判断元素在可视区域内?
Dandelion 10/3/2022 JS
# 概述
# 基本概念
可视区域:浏览网页时,设备内肉眼可见的区域。
在日常开发中,经常需要判断目标元素是否在视窗之内或者和视窗的距离小于一个值。
- 可视区域的运用场景
- 实现方式
- offset 系列(只读)
offsetTop
:元素的上外边框至包含元素的上内边框之间的像素距离offsetLeft
:元素的左外边框至包含元素的左内边框之间的像素距离offsetWidth
:content + padding(左右) + margin(左右)offsetHeight
:content + padding(上下) + margin(上下)
- client 系列(只读)
clientWidth
:content + padding(左右)clientHeight
:content + padding(上下)
- scroll 系列(只读)
scrollTop
:垂直滚动的距离,设为 0 可重置元素滚动位置scrollLeft
:水平滚动的距离,设为 0 可重置元素滚动位置scrollWidth
:用于确定元素的实际滚动宽度scrollHeight
:用于确定元素的实际滚动高度
# offsetTop scrollTop
公式表示:
el.offsetTop - document.documentElement.scrollTop <= viewPortHeight
代码实现:
function isInViewPort(el) { const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; const offsetTop = el.offsetTop; const scrollTop = document.documentElement.scrollTop; return offsetTop - scrollTop <= viewPortHeight; }
1
2
3
4
5
6
7
8
9
# getBoundingClientRect
该方法的返回值是一个 DOMRect 对象,拥有 left/top/right/bottom/x/y/width/height 属性。
left/right:视窗的左边界分别到元素的左边框和右边框的距离。
top/bottom:视窗的上边界分别到元素的上边框和下边框的距离。
当页面发生滚动的时候,left/top/right/bottom 属性值都会随之改变。
如果一个元素在视窗之内的话,那么它一定满足下述条件:
- top >= 0 且 left >= 0
- bottom 小于等于视窗高度
- right 小于等于视窗宽度
代码实现:
function isInViewPort(el) { 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
# Intersection Observer
重叠观察者
:用于判断两个元素是否重叠,因为不用进行事件的监听,性能方面相比 getBoundingClientRect 会好很多。
创建观察者
const options = { // 表示重叠面积占被观察者的比例(0-1),1 表示完全被包含 threshold: 1.0, // 必须是目标元素的父级元素 root: document.querySelector('#scrollArea'), }; const callback = function (entries, observer) { entries.forEach((entry) => { entry.time; // 触发的时间 entry.rootBounds; // 根元素的位置矩形,这种情况下为视窗位置 entry.boundingClientRect; // 被观察者的位置矩形 entry.intersectionRect; // 重叠区域的位置矩形 entry.intersectionRatio; // 重叠区域占被观察者面积的比例(被观察者不是矩形时也按照矩形计算) entry.target; // 被观察者 }); }; const observer = new IntersectionObserver(callback, options);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19传入被观察者
const target = document.querySelector('.target'); observer.observe(target);
1
2