ResizeObserver和IntersectionObserver的详细讲解
ResizeObserver 的介绍
ResizeObserver 用于异步观察元素的尺寸变化。
如:SVG 元素或文本节点的大小变化、调整浏览器窗口大小、动态改变某个元素的大小时
可以触发相应的回调处理逻辑。
当这些目标的大小变化时,ResizeObserver 将会触发一个回调函数
特别提醒:ResizeObserver 在初始观察元素时就会触发回调
Resize 读音:/ˌriːˈsaɪ z/
Observer 读音:/əbˈzɜː və(r)/
ResizeObserver的基本语法
const target = document.getElementById('xx')
ResizeObserver.observe(target,{box: "content-box"})
target 表示需要观察的元素,必须填写
box属性:指定监听的盒模型类型,可选值。包括有下面的值
"content-box"(默认值):监听内容区域尺寸变化
"border-box":监听包含边框和内边距的尺寸变化
"device-pixel-content-box":监听设备像素相关的尺寸变化(适用于高精度场景)
ResizeObserver的基本使用
1,首先获取需要被观察的元素
2,创建实例对象,对象发生变化后需要处理的业务逻辑
const ResizeObserver = new ResizeObserver((entriesArr)=>{
entriesArr.forEach(entry => {
console.log('变化元素尺寸需要处理的业务逻辑:', entry.contentRect);
});
})
3,最后通过resizeObserver.observe(target) 进行进行观察
下面请看如何具体的使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
padding: 0;
margin: 0;
}
#divElement{
width: 100%;
height: 40px;
line-height: 40px;
text-align: center;
background-color: pink;
}
</style>
</head>
<body>
<div id="divElement">我是一个元素</div>
</body>
<script>
// 获取需要被观察的元素(被观察的对象)
const divElement = document.getElementById('divElement')
// 创建一个观察器实例并传入回调函数
const resizeObserver = new ResizeObserver(entriesArr => {
for (let entry of entriesArr) {
console.log('Element:', entry.target);
// 输出元素的宽度和高度
console.log('New size:',entry.contentRect.width, 'x', entry.contentRect.height);
}
});
// 观察一个指定的元素
resizeObserver.observe(divElement);
</script>
</html>

ResizeObserver 在初始观察元素时就会触发回调?
是的,在初始观察元素时。
ResizeObserver 会立即执行一次回调,以提供元素的初始尺寸。
这样设计的好处是:我们可以立即获取到元素的尺寸。
ResizeObserver如何一次性监听多个目标
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
padding: 0;
margin: 0;
}
.box{
display: flex;
}
.ele{
width: 100%;
height: 40px;
line-height: 40px;
text-align: center;
background-color: pink;
margin-left: 5px;
margin-right: 5px;
}
</style>
</head>
<body>
<div class="box">
<div class="ele">我是第1个元素</div>
<div class="ele">我是第2个元素</div>
<div class="ele">我是第3个元素</div>
</div>
<button id="btn">停止观察</button>
</body>
<script>
const observer = new ResizeObserver(entriesArr => {
// entriesArr 是一个数组,表示的是每一个被观察的元素
console.log("entriesArr", entriesArr)
entriesArr.forEach(item => {
console.log(`元素尺寸:${item.contentRect.width} x ${item.contentRect.height}`);
});
});
// 监听多个元素
document.querySelectorAll('.ele').forEach(elem => {
observer.observe(elem);
});
// 点击按钮后,会停止观察所有的元素
const btn=document.getElementById('btn')
btn.addEventListener('click',()=>{
observer.disconnect()
})
</script>
</html>

停止观察特定的目标元素
有些时候我们不需要在观察某个特定的目标
此时,可以停止观察这个特定的目标,它对于性能优化有非常大的作用。
语法:resizeObserver.unobserve("停止观察的元素");
当我们缩放屏幕的时候,我们可以发现在控制台会有输出元素的宽高。

当我们点击停止观察后,控制台不会在有输出,因为我们停止观察这个元素了。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
padding: 0;
margin: 0;
}
#divElement{
width: 100%;
height: 40px;
line-height: 40px;
text-align: center;
background-color: pink;
}
</style>
</head>
<body>
<div id="divElement">我是一个元素</div>
<button id="btn">停止观察</button>
</body>
<script>
// 获取需要被观察的元素(被观察的对象)
const divElement = document.getElementById('divElement')
// 创建一个观察器实例并传入回调函数
const resizeObserver = new ResizeObserver(entries => {
for (let entry of entries) {
console.log('Element:', entry.target);
console.log('New size:',entry.contentRect.width, 'x', entry.contentRect.height);
}
});
// 观察一个指定的元素
resizeObserver.observe(divElement);
// 点击按钮后,会停止观察这个元素
const btn=document.getElementById('btn')
btn.addEventListener('click',()=>{
resizeObserver.unobserve(divElement)
})
</script>
</html>
disconnect 停止观察所有目标元素
disconnect可以停止观察所有目标元素。
效果与unobserve相同
他们之间的区别是:disconnect 是停止所有的。
unobserve是停止特定的某个元素
...其他代码保持不变
// 点击按钮后,停止观察所有目标元素
const btn=document.getElementById('btn')
btn.addEventListener('click',()=>{
resizeObserver.disconnect()
})
contentRect 的含义
细心的小伙伴发现了,我们在获取宽高的使用使用了 xxx.contentRect.width来获取。
这个contentRect 是啥东西?
其实:contentRect 是一个 DOMRectReadOnly 对象,包含以下只读属性
width:元素内容区域的宽度(不含 padding/border)
height:元素内容区域的高度
x/y:内容区域相对于根元素(或视口)的坐标
top/left/right/bottom:内容区域的边界位置
低版本浏览器如何处理
如果担心ResizeObserver的兼容性可使用resize-observer-polyfill这个插件
首先: npm install resize-observer-polyfill --save-dev
使用如下
import ResizeObserver from 'resize-observer-polyfill';
const plugInObserver = new ResizeObserver((entriesArr, observer) => {
for (const entry of entriesArr) {
const { contentRect } = entry; // 这里使用了结构的哈
console.log('Element resized:', contentRect);
}
});
// 获取需要监听的DOM元素
const element = document.getElementById('yourElement');
plugInObserver.observe(element);
用节流提升性能
如果触发的很频繁的话,我们可以使用节流的方式来降低触发频率
function throttle(func, delay) {
let begin = 0;
return function () {
var cur = new Date().getTime();
if (cur - begin > delay) {
func.apply(this, arguments)
begin = cur
}
}
}
const myObserver = new ResizeObserver(throttle(entriesArr=> {
entriesArr.forEach(entry => {
console.log('大小位置 contentRect', entry.contentRect)
console.log('监听的DOM target', entry.target)
})
}), 200)
IntersectionObserver的简单介绍
IntersectionObserver API是用来观察元素是否可见,通常被我们叫做:“交叉观察器”。
和 ResizeObserver 一样,在初始观察元素时就会触发回调函数
Intersection 读音:/ɪn tə ˈse k ʃn/ 十字路口,交叉,交点
ResizeObserver 的观察配置
ResizeObserver 有3个非常重要的配置项。
let options = {
root: null, // 观察目标的上层元素。如:父级元素。爷爷元素。默认为视口。
rootMargin: '0px', // 视口向外扩展的距离
threshold: 0.1 // 观察对象与视口交叉的范围,取值[0,1]。0表示碰上。1表示要完全看见。
// 0.1表示:目标元素与视口可见比例达到 10% 时触发回调
};
let watchObject = new IntersectionObserver(()=>{
console.log('触发时执行的回调函数')
}, options);
rootMargin视口向外扩展的距离

IntersectionObserver的使用场景
1,懒加载图片
2,无限滚动加载
3,展示加载动画
下面我们就使用IntersectionObserver实现懒加载。
让大伙更加熟悉这个api的实验
停止观察
disconnect() 停止监视所有目标元素的可见性变化并销毁观察者。
unobserve(targetElement) 停止观察指定的目标元素
静态布局
静态页面,先写一下图片的布局。
图片的src设置为空,真实的地址在自定义属性data-rsc中。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
padding: 0;
margin: 0;
}
.img-max-box{
display: flex;
flex-wrap: wrap;
margin-top: 20px;
}
.img-container{
width: 484px;
margin-left: 20px;
height: 300px;
margin-bottom: 20px;
}
img{
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div class="img-max-box">
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
</div>
</body>
<script>
</script>
</html>

使用IntersectionObserver实现懒加载
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
padding: 0;
margin: 0;
}
.img-max-box{
display: flex;
flex-wrap: wrap;
margin-top: 20px;
}
.img-container{
width: 484px;
margin-left: 20px;
height: 300px;
margin-bottom: 20px;
}
img{
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div class="img-max-box">
<div class="img-container">
<img src="" data-src="https://plus.unsplash.com/premium_photo-1666278379770-440439b08656?w=600&auto=format&fit=crop&q=60&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8YW5pbWFsc3xlbnwwfHwwfHx8MA%3D%3D"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.unsplash.com/photo-1529778873920-4da4926a72c2?w=600&auto=format&fit=crop&q=60&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxzZWFyY2h8Mnx8YW5pbWFsc3xlbnwwfHwwfHx8MA%3D%3D"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
<div class="img-container">
<img src="" data-src="https://images.pexels.com/photos/106399/pexels-photo-106399.jpeg"/>
</div>
</div>
</body>
<script>
const watchObject = new IntersectionObserver((entriesArr)=>{
console.log('触发了这个函数', entriesArr);
// entriesArr 是一个数组。里面是被观察的元素。目前我有20个图片。因此数组的长度为20
entriesArr.forEach((entryItem)=>{
// entryItem 是一个对象。里面有isIntersecting属性。
// 表示是否与视口交叉。true表示交叉了。 false表示没有交叉。
if(entryItem.isIntersecting){
console.log('交叉了');
entryItem.target.src = entryItem.target.dataset.src;
// 停止观察这个元素,因为这个元素已经获取到图片了
watchObject.unobserve(entryItem.target);
}
})
},{
threshold: 0 // 观察对象与视口交叉的范围。取值[0,1],0表示碰上就会执行回调。1表示要完全看见。
})
const imgArr = document.querySelectorAll('img');
imgArr.forEach((imgItem)=>{
// 开始进行观察
watchObject.observe(imgItem);
})
</script>
</html>

intersectionRatio,isIntersecting,target,time属性的详细讲解
intersectionRatio:number
表示目标元素与根元素的交叉区域的比例,即交叉区域面积与目标元素总面积的比值。
当目标元素完全可见时,值为1;完全不可见时,值为0。返回的是一个类型的值
如果元素部分可见,则是一个介于0和1之间的值。
isIntersecting:boolean
表示目标元素是否与根元素相交(交叉)。如果相交(即使交叉区域为零)则为true;否则为false。
true: 当元素开始进入或仍在交叉区域
false: 当元素完全离开交叉区域
target:Element
表示:被观察的目标元素。
用途: 在多个观察目标中识别当前触发的元素
time: number
描述: 交叉状态变化的时间戳(从页面加载开始计算,单位:毫秒)
用途:1,计算交叉事件的精确时间。2,性能分析(如计算元素进入视口的耗时)

尾声
今天周五啦,开心
ResizeObserver和IntersectionObserver的详细讲解的更多相关文章
- head标签详细讲解
head标签详细讲解 head位于html网页的头部,后前的标签,并以开始以结束的一html标签. Head标签位置如图: head标签示意图 head包含标签 meta,title,link,bas ...
- 详细讲解nodejs中使用socket的私聊的方式
详细讲解nodejs中使用socket的私聊的方式 在上一次我使用nodejs+express+socketio+mysql搭建聊天室,这基本上就是从socket.io的官网上的一份教程式复制学习,然 ...
- iOS KVC详细讲解
iOS KVC详细讲解 什么是KVC? KVC即NSKeyValueCoding,就是键-值编码的意思.一个非正式的 Protocol,是一种间接访问对象的属性使用字符串来标识属性,而不是通过调用存取 ...
- Android webservice的用法详细讲解
Android webservice的用法详细讲解 看到有很多朋友对WebService还不是很了解,在此就详细的讲讲WebService,争取说得明白吧.此文章采用的项目是我毕业设计的webserv ...
- 详细讲解Android对自己的应用代码进行混淆加密防止反编译
1.查看项目中有没有proguard.cfg. 2.如果没有那就看看这个文件中写的什么吧,看完后将他复制到你的项目中. -optimizationpasses 5 -dontusemixedcasec ...
- 详细讲解Hadoop源码阅读工程(以hadoop-2.6.0-src.tar.gz和hadoop-2.6.0-cdh5.4.5-src.tar.gz为代表)
首先,说的是,本人到现在为止,已经玩过. 对于,这样的软件,博友,可以去看我博客的相关博文.在此,不一一赘述! Eclipse *版本 Eclipse *下载 Jd ...
- [iOS]数据库第三方框架FMDB详细讲解
[iOS]数据库第三方框架FMDB详细讲解 初识FMDB iOS中原生的SQLite API在进行数据存储的时候,需要使用C语言中的函数,操作比较麻烦.于是,就出现了一系列将SQLite API进行封 ...
- jquery插件分类与编写详细讲解
jquery插件分类与编写详细讲解 1. 插件种类 插件其实就是对现有的方法(或者叫函数)做一个封装,方便重用提高开发效率. jQeury主要有2种类型 1)实例对象方法插件 开发能让所有的j ...
- [VC++]用CTime类得到当前日期、时间、星期,格式化(详细讲解)
用CTime类得到当前日期.时间.星期,格式化(详细讲解)2009/05/12 09:48 A.M.① 定义一个CTime类对象 CTime time; ② 得到当前时间 time = CTime:: ...
- (三)Jquery Mobile按钮详细讲解
Jquery Mobile按钮详细讲解 一.JM按钮说明 按钮如下图所示 1.HTML5中的button 效果: 2. JM中的普通button ...
随机推荐
- 昨晚接收的俄罗斯Meteor-M2气象卫星云图,接收质量还可以!
接收设备: 天馈:自制四臂螺旋天线 硬件:SDRsharp 跟踪:Orbitron.SDRSharpDriverDDE 频率:137.1MHZ 解码:SDRSharp.QPSK.M2_LRPT_Dec ...
- 出现TypeError: float() argument must be a string or a number, not _NoValueType(机器学习 Win11)
博客地址:https://www.cnblogs.com/zylyehuo/ 如果出现以下报错 则说明是torch.numpy等库的版本不匹配 可以去以下网站寻找匹配的版本 https://mirro ...
- c#数据库操作ORM映射框架
主要功能介绍 支持Oracle,SQL Server,MySQL,SQLLite等数据库..主要功能: 支持查询返回动态类型Dynamic以及可扩展类型ExpandoDynamic 表拆分,根据某个日 ...
- Linux下使用fdisk扩大分区容量
磁盘容量有300GB,之前分区的时候只分了一个150GB的/data分区,现在/data分区已经不够用了. 需求:把这块磁盘剩余的150GB容量增加到之前的/data分区,并且保证/data分区原有的 ...
- VS2019如何将主菜单从标题栏移到单独一行
vs2019安装后默认将菜单栏放在标题栏位置,这给我们日常使用带来些许不便 多窗口不能直观看到项目名 小屏幕上可以用来拖动窗口的区域太小 下面是恢复经典标题栏和菜单栏位置的方法 工具->选项-& ...
- 基于.NetCore开发 StarBlog 番外篇 (2) 深入解析Markdig源码,优化ToC标题提取和文章目录树生成逻辑
前言 虽然现在工作重心以AI为主了,不过相比起各种大模型的宏大叙事,我还是更喜欢自己构思功能.写代码,享受解决问题和发布上线的过程. 之前 StarBlog 系列更新的时候我也有提到,随着功能更新,会 ...
- 技术博客:如何构建AI模拟面试系统(附完整GitHub代码)
引言:当董明珠.雷军.马斯克和特朗普成为你的面试官 在当今竞争激烈的求职市场中,模拟面试系统正成为开发者提升竞争力的秘密武器.但传统的模拟面试太过平淡,于是我开发了一个多风格AI面试官系统,让你可以体 ...
- vscode安装离线插件autopep8
商店 从上面的链接进去,在visual studio code一栏开始搜索,我要的是autopep8,所以搜索得到的是这样的: 点进去后,是这个界面,然后我是离线下载,要的是拓展包,所以是下面操作 下 ...
- Tomcat日志拆分(linux)
1.新增shell脚本[tomcat_catalina.sh] #!/bin/bash #设置日志文件存放目录 LOG_HOME="/app/server/tomcat/tomcat-808 ...
- MySQL 数据库的性能优化方法有哪些?
MySQL 数据库性能优化是提高数据库响应速度和处理能力的重要手段.性能优化可以从多个层面入手,涵盖数据库设计.查询优化.硬件资源优化.配置调整等方面.以下是 MySQL 数据库常见的性能优化方法: ...