当前位置:网站首页>面试官问:如何判断一个元素是否在可视区域?
面试官问:如何判断一个元素是否在可视区域?
2022-07-27 13:29:00 【夏安 】
面试官问:如何判断一个元素是否在可视区域?
面试官问:如何判断一个元素是否在可视区域?
最近在参加面试找工作,陆陆续续的面了两三家。其中一个面试官问到了一个问题:如何判断一个元素是否在可视区域?由于平时处理的不多,所以一时没有回答出来,后来研究了下,所以有了这篇文章。
1. 通过元素的位置信息和滚动条滚动的高度
在这里,我们先介绍几个元素的位置信息和大小:
Element.clientWidth
Element.clientWidth 属性表示元素的内部高度,以像素计。该属性包括内边距 padding,但不包括边框 border、外边距 margin 和水平滚动条(如果有的话)。所以 clientHeight 可以通过 CSS height + CSS padding - 水平滚动条高度 (如果存在) 来计算。同理还有 Element.clientHeight 属性。
备注: 此属性会将获取的值四舍五入取整数。
window.innerHeight
window.innerHeight 属性表示浏览器窗口的视口(viewport)高度(以像素为单位);如果有水平滚动条,也包括滚动条高度。同理还有 Element.clientWidth 属性。
HTMLElement.offsetTop
HTMLElement.offsetTop返回当前元素相对于其 offsetParent 元素的顶部内边距的距离。那么offsetParent 又是怎么回事呢?
HTMLElement.offsetParent
HTMLElement.offsetParent返回一个指向最近的(指包含层级上的最近)包含该元素的定位元素或者最近的 table,td,th,body元素。当元素的 style.display 设置为 "none" 时,offsetParent 返回 null。offsetParent 很有用,因为 offsetTop 和 offsetLeft 都是相对于其内边距边界的。
好了,了解完这些属性之后,自然明白了下面的判断方法:
function isInViewPort(element) {
// 获取可视窗口的高度。
const screenHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
// 获取滚动条滚动的高度
const scrollTop = document.documentElement.scrollTop;
// 获取元素偏移的高度。就是距离可视窗口的偏移量。
const offsetTop = element.offsetTop;
return offsetTop - scrollTop <= screenHeight;
}
可能这个时候读者会有疑问:为什么要用 screenHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight 这么长的代码来获取可视窗口的高度呢?这里是为了兼容所有浏览器写法。
2. 通过getBoundingClientRect方法来获取元素的位置信息
Element.getBoundingClientRect() 方法返回一个 DOMRect 对象,其提供了元素的大小及其相对于视口的位置。那么问题又来了,DOMRect 对象又是什么呢?DOMRect 可以理解为将元素看出一个矩形,该对象包含了该矩形的位置、大小信息,可以获得页面中元素的左,上,右和下分别相对浏览器视窗的位置。
Element.getBoundingClientRect().top表示元素上边距离页面上边的距离Element.getBoundingClientRect().right表示元素右边距离页面左边的距离Element.getBoundingClientRect().bottom表示元素下边距离页面上边的距离Element.getBoundingClientRect().left表示元素左边距离页面左边的距离

当页面发生滚动的时候,它们会随之改变。如果一个元素在视窗之内的话,那么它一定满足下面四个条件:
top大于等于 0left大于等于 0bottom小于等于视窗高度right小于等于视窗宽度
function isContain(dom) {
const viewHeigh = window.innerHeight || document.documentElement.clientHeight;
const viewWidth = window.innerWidth || document.documentElement.clientWidth;
// 当滚动条滚动时,top, left, bottom, right时刻会发生改变。
const {
top,
right,
bottom,
left
} = dom.getBoundingClientRect();
return (top >= 0 && left >= 0 && right <= viewWidth && bottom <= viewHeight);
}
3. 通过Intersection Observer来实现监听
Intersection Observer 接口 (从属于Intersection Observer API) 提供了一种异步观察目标元素与其祖先元素或顶级文档视窗 (viewport) 交叉状态的方法。祖先元素与视窗 (viewport) 被称为根 (root)。
当一个Intersection Observer对象被创建时,其被配置为监听根中一段给定比例的可见区域。一旦 Intersection Observer 被创建,则无法更改其配置,所以一个给定的观察者对象只能用来监听可见区域的特定变化值;然而,你可以在同一个观察者对象中配置监听多个目标元素。
接下来我们先来看看它的用法:
3.1 API
var io = new IntersectionObserver(callback, option);
上面代码中,IntersectionObserver 是浏览器原生提供的构造函数,接受两个参数:
callback是可见性变化时的回调函数option是配置对象(该参数可选)
构造函数的返回值是一个观察器实例。实例的 observe 方法可以指定观察哪个 DOM 节点。
// 开始观察
io.observe(document.getElementById('example'));
// 停止观察
io.unobserve(element);
// 关闭观察器
io.disconnect();
上面代码中,observe 的参数是一个 DOM 节点对象。如果要观察多个节点,就要多次调用这个方法。
io.observe(elementA);
io.observe(elementB);
3.2 callback 参数
目标元素的可见性变化时,就会调用观察器的回调函数 callback。callback一般会触发两次。一次是目标元素刚刚进入视口(开始可见),另一次是完全离开视口(开始不可见)。
var io = new IntersectionObserver(
entries => {
console.log(entries);
}
);
上面代码中,回调函数采用的是箭头函数的写法。callback 函数的参数(entries)是一个数组,每个成员都是一个 IntersectionObserverEntry 对象。举例来说,如果同时有两个被观察的对象的可见性发生变化,entries 数组就会有两个成员
3.3 IntersectionObserverEntry 对象
IntersectionObserverEntry 对象提供目标元素的信息,一共有六个属性。
{
time: 3893.92,
rootBounds: ClientRect {
bottom: 920,
height: 1024,
left: 0,
right: 1024,
top: 0,
width: 920
},
boundingClientRect: ClientRect {
// ...
},
intersectionRect: ClientRect {
// ...
},
intersectionRatio: 0.54,
target: element
}
每个属性的含义如下。
time:可见性发生变化的时间,是一个高精度时间戳,单位为毫秒target:被观察的目标元素,是一个 DOM 节点对象rootBounds:根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回nullboundingClientRect:目标元素的矩形区域的信息intersectionRect:目标元素与视口(或根元素)的交叉区域的信息intersectionRatio:目标元素的可见比例,即intersectionRect占boundingClientRect的比例,完全可见时为1,完全不可见时小于等于0
3.4 Option 对象
IntersectionObserver 构造函数的第二个参数是一个配置对象。它可以设置以下属性。
threshold属性
threshold 属性决定了什么时候触发回调函数。它是一个数组,每个成员都是一个门槛值,默认为 [0],即交叉比例(intersectionRatio)达到 0 时触发回调函数。
new IntersectionObserver(
entries => {
/* ... */},
{
threshold: [0, 0.25, 0.5, 0.75, 1]
}
);
用户可以自定义这个数组。比如,[0, 0.25, 0.5, 0.75, 1] 就表示当目标元素 0%、25%、50%、75%、100% 可见时,会触发回调函数。
root属性,rootMargin属性
很多时候,目标元素不仅会随着窗口滚动,还会在容器里面滚动(比如在iframe窗口里滚动)。容器内滚动也会影响目标元素的可见性。
IntersectionObserver API 支持容器内滚动。root 属性指定目标元素所在的容器节点(即根元素)。注意,容器元素必须是目标元素的祖先节点。
var opts = {
root: document.querySelector('.container'),
rootMargin: "500px 0px"
};
var observer = new IntersectionObserver(
callback,
opts
);
上面代码中,除了 root 属性,还有 rootMargin 属性。后者定义根元素的 margin,用来扩展或缩小 rootBounds 这个矩形的大小,从而影响 intersectionRect 交叉区域的大小。它使用 CSS 的定义方法,比如 10px 20px 30px 40px,表示 top、right、bottom 和 left 四个方向的值。这样设置以后,不管是窗口滚动或者容器内滚动,只要目标元素可见性变化,都会触发观察器。
4. 应用场景
- 图片的懒加载
有时,我们希望某些静态资源(比如图片),只有用户向下滚动,它们进入视口时才加载,这样可以节省带宽,提高网页性能。
- 列表的无限滚动
无限滚动时,最好在页面底部有一个页尾栏。一旦页尾栏可见,就表示用户到达了页面底部,从而加载新的条目放在页尾栏前面。
边栏推荐
- Group division and characteristic analysis of depression patients based on online consultation records
- Document translation__ Tvreg V2: variational imaging method for denoising, deconvolution, repair and segmentation (part)
- Shell编程规范与变量
- 汉字风格迁移篇---对抗性区分域适应(L1)Adversarial Discriminative Domain Adaptation
- How to solve cache avalanche, breakdown and penetration problems
- Is the security of online brokerage app account opening guaranteed?
- C语言基础练习题目
- 次小生成树【模板】
- 在Oracle VirtualBox中导入Kali Linux官方制作的虚拟机
- PROFINET 模拟器使用教程
猜你喜欢

Construction and empirical research of post talent demand analysis framework based on recruitment advertisement
![[related contents of multithreading]](/img/2d/c8bde21f13a5305ba54e9b52bd1e89.png)
[related contents of multithreading]

C语言基础知识梳理总结

Navicate报错access violation at address 00000000

PROFINET simulator tutorial

Utnet hybrid transformer for medical image segmentation

Schematic diagram of C measuring tool

融合迁移学习与文本增强的中文成语隐喻知识识别与关联研究

Arduino+ze08-ch2o formaldehyde module, output formaldehyde content

codeforces 1708E - DFS Trees
随机推荐
次小生成树【模板】
文献翻译__基于自适应全变差L1正则化的椒盐图像去噪
开源版思源怎么私有部署
力扣SQL语句习题,错题记录
DVWA全级别通关教程
Schematic diagram of C measuring tool
np. Usage and difference of range() and range()
Architecture - the sublimation of MVC
Airport cloud business sign analysis
Named entity recognition of Chinese electronic medical records based on Roberta WwM dynamic fusion model
Database storage series (1) column storage
This points to problems, closures, and recursion
Electronic bidding procurement mall system: optimize traditional procurement business and speed up enterprise digital upgrading
MySQL advanced II. Logical architecture analysis
Utnet hybrid transformer for medical image segmentation
连接ResourceManager 失败
User question understanding and answer content organization for epidemic disease Science Popularization
Document translation__ Salt and pepper image denoising based on adaptive total variation L1 regularization
Carla notes (04) - client and world (create client, connect world, batch object, set weather, set lights, world snapshots)
这年头谁还不会抓包,WireShark 抓包及常用协议分析送给你!