网站怎么生成二维码,制作好看的wordpress页面,fomo3d 网站怎么做,设计游戏的软件IntersectionObserver#xff1a;
一个元素从不可见到可见#xff0c;从可见到不可见
??IntersectionObserver是一种浏览器提供的 JavaScript API#xff0c;用于监测元素与视窗的交叉状态。它可以告诉开发者一个元素是否进入或离开视窗#xff0c;以及两者的交叉区域的…IntersectionObserver
一个元素从不可见到可见从可见到不可见
??IntersectionObserver是一种浏览器提供的 JavaScript API用于监测元素与视窗的交叉状态。它可以告诉开发者一个元素是否进入或离开视窗以及两者的交叉区域的大小和位置。 它提供了一种高效的方法来观察元素是否进入或离开视窗而无需依赖滚动事件或定时器。它可以通过回调函数及设定的阈值来实时地通知开发者目标元素与视窗的交叉状态并根据需要采取相应的操作。
特性
异步执行IntersectionObserver 是异步执行的它使用浏览器的内部优化机制不会阻塞主线程从而避免了性能问题。节省资源相比于传统的滚动事件或定时器IntersectionObserver 可以精确地观察元素与视窗的交叉状态避免了不必要的计算和回调触发从而节省了资源的消耗。多目标观察IntersectionObserver 可以同时观察多个目标元素通过回调函数逐个通知开发者它们的交叉状态方便进行批量操作。自定义阈值开发者可以设定一个或多个阈值用来定义元素与视窗的交叉比例。当交叉比例超过或低于阈值时会触发相应的回调函数。
API介绍
**IntersectionObserver(callback, options)**创建新的实例传入回调函数和配置对象。**observe(target)**观察指定目标元素传入目标元素。**unobserve(target)**停止观察指定目标元素。**disconnect()**停止观察断开与所有目标元素的关联。
创建一个交叉观察器
通过调用 IntersectionObserver 构造函数创建交叉观测器并将回调函数传给它当一个方向或另一个方向越过阈值时就运行该函数
let options {root: document.querySelector(#scrollArea),rootMargin: 0px,threshold: 1.0,
};let observer new IntersectionObserver(callback, options);阈值为 1.0 意味着目标元素完全出现在root选项指定的元素中 100% 可见时回调函数将会被执行。
IntersectionObserver 选项
传递到IntersectionObserver()构造函数的options对象可以控制在什么情况下调用观察器的回调。它有以下字段
root
用作视口的元素用于检查目标的可见性。必须是目标的祖先。如果未指定或为null则默认为浏览器视口。
rootMargin
根周围的边距。其值可以类似于 CSSmargin属性例如10px 20px 30px 40px上、右、下、左。这些值可以是百分比。在计算交叉点之前这组值用于增大或缩小根元素边框的每一侧。默认值为全零。
threshold
一个数字或一个数字数组表示目标可见度达到多少百分比时观察器的回调就应该执行。如果只想在能见度超过 50% 时检测可以使用 0.5 的值。如果希望每次能见度超过 25% 时都执行回调则需要指定数组 [0, 0.25, 0.5, 0.75, 1]。默认值为 0这意味着只要有一个像素可见回调就会运行。值为 1.0 意味着在每个像素都可见之前阈值不会被认为已通过。
定位要观察的元素
创建一个观察器后需要给定一个目标元素进行观察。
let target document.querySelector(#listItem);
observer.observe(target);// 我们为观察器设置的回调将在第一次执行
// 它将等待我们为观察器分配目标即使目标当前不可见每当目标满足该IntersectionObserver指定的阈值threshold回调被调用。回调接收IntersectionObserverEntry对象和观察器的列表
let callback (entries, observer) {entries.forEach((entry) {// 每个条目描述一个目标元素观测点的交叉变化// entry.boundingClientRect// entry.intersectionRatio// entry.intersectionRect// entry.isIntersecting// entry.rootBounds// entry.target// entry.time});
};其中entry对象包括以下这些参数 **entry.boundingClientRect**当前观察元素的矩形区域top/right/bottom/left属性可以获得此时相对视区的距离width/height属性包含尺寸。此属性和Element.getBoundingClientRect()这个API方法非常类似。 **entry.intersectionRatio**当前元素被交叉的比例。比例要想非常详细需要IntersectionObserver()函数的第2个可选参数中设置thresholds参数也就是设置触发交叉事件的阈值。 **entry.intersectionRect**和视区交叉的矩形大小。 **entry.isIntersecting**如果是true则表示元素从视区外进入视区内。 **entry.rootBounds**窗体根元素的矩形区域对象。 **entry.target**当前交叉的元素。 entry.time当前时间戳。 举个栗子
var zxxObserver new IntersectionObserver(function (entries) {entries.forEach(function (entry) {if (entry.isIntersecting) {// entry.target元素进入区域了}});
});
// 观察元素1,2,...
zxxObserver.observe(ele1);
zxxObserver.observe(ele2);
...用文字解释下就是这两步
定义元素交叉后干嘛干嘛需要观察那些元素
实际开发的时候主要工作就是对entries.forEach这部分的代码进行处理。
应用场景
探秘神奇的IntersectionObserver释放网页性能的黑科技IntersectionObserver 提供 - 掘金
图片懒加载
通过使用IntersectionObserver可以延迟加载图片只在它们进入视窗时才开始加载。这样可以减少初始页面加载时间并节省带宽和资源。 实现图片懒加载的步骤如下 创建IntersectionObserver实例并指定观察的目标元素。在回调函数中判断目标元素是否进入视窗。若目标元素进入视窗将其真实的图片地址赋给元素的src属性触发图片加载。 把所有需要延迟加载的图片用一个盒子包起来设置宽高和默认占位图 开始让所有IMG的SRC为空把真实图片的地址放到IMG的自定义属性上让IMG隐藏 等到所有其他资源都加载完成后再开始加载图片 对于很多图片需要当页面滚动的时候当前图片区域显示出来后在加载真实图片 import { useEffect, useRef } from react
import styles from ./LazyImg.module.scssconst Index () {const ImgRef useRefHTMLDivElement(null)const handleLoad (entries: IntersectionObserverEntry[]) {entries.forEach(entry {if (entry.isIntersecting) {const img entry.target as HTMLImageElement;img.src img.getAttribute(data-src) || ; // 将真实的图片地址赋给 src 属性intersectionObserver.unobserve(img); // 停止观察该图片}})}const intersectionObserver new IntersectionObserver(handleLoad)useEffect(() {if (ImgRef.current) {const imgs ImgRef.current.querySelectorAll(img);imgs.forEach(img {intersectionObserver.observe(img)})}return () {intersectionObserver.disconnect()}}, [])return div className{styles.main_box} ref{ImgRef}img src alt data-src../assets/module182_style1.png /img src alt data-src../assets/module182_style2.png /img src alt data-src../assets/module182_style1.png //div/
}export default Index用户兴趣埋点 规则是当某元素在视口停留时间达到2秒以上时被认为用户对该元素感兴趣。 步骤如下 创建 IntersectionObserver 实例并指定观察的目标元素。在回调函数中根据目标元素的交叉状态判断用户对该元素的兴趣。根据规则判断适口停留时间是否满足条件。如果满足条件则记录兴趣数据或触发相应操作。 import { useEffect, useRef } from reactconst Index () {const BuriedRef useRefHTMLDivElement(null)const handleBuried (entries: IntersectionObserverEntry[]) {entries.forEach(entry {if (entry.isIntersecting entry.intersectionRatio 0.5 entry.intersectionRect.width entry.boundingClientRect.width * 0.5 entry.intersectionRect.height entry.boundingClientRect.height * 0.5 entry.time 2000) {// 埋点操作}})}const intersectionObserver new IntersectionObserver(handleBuried)useEffect(() {if (BuriedRef.current) {const boxs BuriedRef.current.querySelectorAll(item);boxs.forEach(box { intersectionObserver.observe(box) })}return () {intersectionObserver.disconnect()}}, [])return div ref{BuriedRef}div classNameitemimg src alt data-src../assets/module182_style1.png //divdiv classNameitemimg src alt data-src../assets/module182_style2.png //divdiv classNameitemimg src alt data-src../assets/module182_style1.png //div/div
}export default Index进阶
优化阈值设置 设置合适的交叉比例阈值可以减少不必要的回调函数触发。过多的阈值设置可能会导致频繁的回调函数执行因此需要根据具体情况进行优化。避免频繁的回调函数执行 由于 IntersectionObserver 可能在短时间内多次触发回调函数为了避免频繁的操作或网络请求可以使用节流throttling或防抖debouncing技术进行处理。节流可以限制回调函数的执行频率而防抖可以在指定时间内的连续触发中只执行最后一次。优化性能与资源消耗 尽管 IntersectionObserver 可以提供更好的性能但当处理大量元素或复杂布局时仍需考虑性能和资源消耗。可以结合使用时间间隔、限制最大触发次数等策略确保在合理的范围内处理交叉状态变化。控制监听范围 仅监听真正需要监测的元素避免不必要的监听。过多的监听会增加性能消耗并可能导致不必要的回调函数触发。谨慎使用多个 IntersectionObserver 当需要监测多个元素时使用多个 IntersectionObserver 可能会增加代码复杂性和性能开销。在这种情况下可以考虑合并监听逻辑减少 IntersectionObserver 的数量。处理边界情况 注意处理边界情况如元素尺寸变化、容器滚动等。在这些情况下IntersectionObserver 可能无法及时检测到交叉状态的变化需要进行额外的处理。考虑兼容性 尽管大多数现代浏览器都支持 IntersectionObserver但在一些旧版本浏览器中可能不被支持。为了确保兼容性可以使用 IntersectionObserver 的 polyfill 或提供降级方案。处理 IntersectionObserver 回调中的异步操作 取消异步操作在某些情况下当元素离开视窗或不再需要异步操作时可能需要取消正在进行的异步操作。例如当用户迅速滚动页面时可能需要取消之前触发的异步操作以避免不必要的网络请求或计算。可以使用适当的方法如取消 Promise 或中断正在进行的异步任务。性能优化对于耗时的异步操作需要注意性能优化。考虑使用并发执行、缓存结果或其他优化策略以减少延迟和资源消耗。 清理资源 当不再需要 IntersectionObserver 监听或元素被销毁时确保正确地清理和释放相关的资源。取消监听、解除绑定和清理回调函数以避免内存泄漏和不必要的资源占用。兼容性尽管现代浏览器大多支持 IntersectionObserver但在一些旧版本的浏览器中可能不被支持。为了确保广泛的兼容性开发者需要根据项目需求考虑是否需要提供降级方案或使用 polyfill。事件顺序不确定性由于 IntersectionObserver 是异步执行的不同元素的回调函数执行顺序是不确定的。这可能会导致在处理相关逻辑时需要额外的注意以确保正确的顺序和逻辑关联性。
MutationObserver
监听元素的属性和子节点的变化
??MutationObserver的目标是解决传统的DOM变化监听方式的局限性和性能问题并提供更高效、灵活的DOM变化监视机制。 在过去开发人员使用DOM事件监听或定时器轮询的方式来监视DOM的变化。
MutationObserver用于监听DOM对象的变更包括节点属性的变化、子节点的增删改等。提供了方便的方式监听DOM变化。
API介绍
**MutationObserver(callback)**创建新的实例传入变动时的回调函数。**observe(target, config)**开始观察指定目标节点传入目标节点和配置对象。**disconnect()**停止观察断开与所有目标节点的关联。takeRecords():从 MutationObserver 的通知队列中删除所有待处理的通知并将它们返回到MutationRecord对象的新Array中。
举个栗子
// 选择需要观察变动的节点
const targetNode document.getElementById(some-id);// 观察器的配置需要观察什么变动
const config { attributes: true, childList: true, subtree: true };// 当观察到变动时执行的回调函数
const callback function (mutationsList, observer) {// Use traditional for loops for IE 11for (let mutation of mutationsList) {if (mutation.type childList) {console.log(A child node has been added or removed.);} else if (mutation.type attributes) {console.log(The mutation.attributeName attribute was modified.);}}
};// 创建一个观察器实例并传入回调函数
const observer new MutationObserver(callback);// 以上述配置开始观察目标节点
observer.observe(targetNode, config);// 之后可停止观察
observer.disconnect();??config对象在MutationObserver的observe方法中用于指定哪些类型的 DOM 变动需要被观察。config对象可以包含以下属性每个属性都是一个布尔值指示是否应该观察对应类型的变动 attributes: 当被观察元素的属性变动时触发。注意这个选项不会捕获class属性的变动除非通过attributeNameFilter明确指定。要捕获class属性的变动可以监视attributeFilter为[class]或者使用子树变动childList和特性变动attributes的组合因为类名的变化通常会导致子节点如span元素用于通过 CSS 类应用样式的添加或移除。 childList: 当被观察元素的子节点变动时触发添加或移除子节点。 subtree: 当被观察元素的所有后代节点变动时触发。这个选项扩大了观察范围使得变动不仅限于直接子节点还包括所有更深层次的子节点。 characterData: 当被观察元素的文本内容变动时触发。这个选项仅对文本节点或设置了nodeType为Node.TEXT_NODE的节点有效。注意如果观察目标是元素节点即使该元素包含文本节点也不会触发此变动类型除非这些文本节点是被单独观察的。 characterDataOldValue: 当文本内容变动时这个选项会被设置为true以捕获变动前的旧值。这个选项仅当characterData也被设置为true时有效。 attributeOldValue: 当属性变动时这个选项会被设置为true以捕获变动前的旧值。这个选项仅当attributes也被设置为true时有效。 attributeFilter: 一个数组包含需要观察变动的属性名称。只有当attributes设置为true时这个选项才有意义。只有指定的属性发生变动时才会触发变动回调。 应用场景
开启DOM观察者模式引爆你的前端开发创造力 - MutationObserverMutationObserver 的 - 掘金
白屏检测
// 创建 MutationObserver 实例
const observer new MutationObserver((mutationsList) {// 遍历每个 DOM 变化记录for (const mutation of mutationsList) {// 检查是否是节点的子节点发生了变化if (mutation.type childList) {// 检查页面是否还有子节点if (document.body.childNodes.length 0) {// 页面处于白屏状态console.log(页面处于白屏状态);} else {// 页面已经加载完成console.log(页面加载完成);}}}
});// 监视整个文档根节点的子节点变化
observer.observe(document.documentElement, {childList: true,subtree: true,
});// 停止监听
// observer.disconnect();编辑器自动保存
??MutationObserver在编辑器自动保存场景中可以用于监测编辑器内容的变化从而实现自动保存功能。通过监听编辑器内容的变化可以在用户输入或编辑内容时自动触发保存操作避免用户因意外关闭页面或其他原因导致的数据丢失。
// 目标编辑器元素
const editor document.getElementById(editor);// 创建 MutationObserver 实例
const observer new MutationObserver((mutationsList) {// 编辑器内容发生变化时触发保存操作saveEditorContent();
});// 监视编辑器内容的子节点变化
observer.observe(editor, { childList: true, subtree: true });// 保存编辑器内容的函数
function saveEditorContent() {// 执行保存操作可以通过 Ajax 请求或其他方式将内容发送到服务器进行保存console.log(正在保存编辑器内容...);
}// 停止监听
// observer.disconnect();防止水印被删除
? ?MutationObserver可以用于防止水印被删除的场景通过监测相关元素的变化可以检测到水印元素是否被删除或修改并及时进行恢复。
// 目标水印元素
const watermark document.getElementById(watermark);// 创建 MutationObserver 实例
const observer new MutationObserver(() {// 水印元素发生变化时重新添加水印restoreWatermark();
});// 监视水印元素的父节点变化
observer.observe(watermark.parentNode, { childList: true });// 恢复水印的函数
function restoreWatermark() {// 检查水印元素是否存在若不存在则重新添加if (!document.contains(watermark)) {// 重新添加水印到目标位置// ...console.log(水印被删除已恢复);}
}// 停止监听
// observer.disconnect();实时搜索和过滤
??MutationObserver在实时搜索和过滤场景中可以用于监测搜索条件的变化并在每次搜索条件发生变化时触发搜索或过滤操作。通过监听搜索条件的变化可以及时响应用户的输入并实时更新搜索结果或过滤列表提供更好的搜索体验。
// 目标搜索输入框元素
const searchInput document.getElementById(searchInput);// 创建 MutationObserver 实例
const observer new MutationObserver(() {// 搜索条件发生变化时执行搜索或过滤操作performSearch();
});// 监视搜索输入框的值变化
observer.observe(searchInput, { characterData: true, subtree: true });// 搜索或过滤操作的函数
function performSearch() {// 获取搜索输入框的值const searchValue searchInput.value.trim();// 执行搜索或过滤操作根据具体需求来实现// ...console.log(Performing search or filter: searchValue);
}// 停止监听
// observer.disconnect();进阶
精确指定目标在创建 MutationObserver 实例时明确指定要观察的目标元素避免过于宽泛的监测范围。这可以提高性能并减少不必要的回调触发。选择合适的观察选项根据需求选择合适的观察选项。常见的选项包括 childList监听子节点的变化、attributes监听属性的变化、characterData监听文本节点内容的变化等。根据实际情况只选择需要监测的选项避免监听不必要的变化。使用 disconnect 方法停止监听在不再需要监听的时候调用 disconnect 方法停止 MutationObserver 的监听。这可以释放资源并避免不必要的回调触发。避免频繁的回调触发回调函数可能会在短时间内多次触发尤其是在监测范围较大或有频繁变化的情况下。在回调函数中尽量避免执行耗时操作以免影响性能。结合其他技术和优化手段MutationObserver 可以与其他技术和优化手段结合使用以实现更好的效果。例如可以结合 Debounce 或 Throttle 技术来限制回调函数的触发频率以减少频繁的回调。浏览器兼容性考虑MutationObserver 在大多数现代浏览器中得到支持但仍需注意浏览器的兼容性。如果需要在旧版本的浏览器中使用 MutationObserver可以考虑使用 polyfill 或其他替代方案。回调函数执行时间回调函数在每次 DOM 更新之后都会被触发因此应尽量避免在回调函数中执行耗时操作以免影响页面的响应性能。无法监测样式变化MutationObserver 默认无法监测样式的变化只能监测到 DOM 结构的变化。如果需要监测样式的变化可以使用 CSSOM 或其他技术进行检测。无法监测属性的初始值变化MutationObserver 只能监测到属性的后续变化而无法监测到属性初始值的变化。如果需要监测属性初始值的变化可以通过其他方法进行检测如在元素创建之前记录初始值。可能触发多次回调在某些情况下MutationObserver 可能会在短时间内触发多次回调尤其是当监测范围较大或有频繁的 DOM 变化时。因此在回调函数中应考虑回调的频率和性能消耗避免执行过多的耗时操作。无法跨域监测和操作由于浏览器的安全策略限制MutationObserver 无法跨域监测和操作 DOM。只能在同域的情况下使用 MutationObserver 进行 DOM 监测。不支持 IE9 及以下版本MutationObserver 不支持 IE9 及以下版本的浏览器如果需要在旧版本的浏览器中使用 MutationObserver可以考虑使用 polyfill 或其他替代方案。注意 DOM 修改的影响在回调函数中对 DOM 进行修改可能会触发新的 DOM 变化从而再次触发 MutationObserver 的回调函数。这可能导致无限循环的情况发生因此在修改 DOM 时要小心谨慎。
ResizeObserver
**??ResizeObserver**接口监视Element内容盒或边框盒或者SVGElement边界尺寸的变化。 同时无需再手动调用getBoundingClientRect来获取元素的尺寸大小它对任何元素大小变化做出反应与引起变化的原因无关。 通知的内容包含了足够的信息以便开发者能够根据当前元素的具体大小信息来作出变化而不是要开发者重新调用getComputedStyle、getBoundingClientRect来获取。 监听元素target。contentRect。contentBoxSize。borderBoxSize。devicePixelContentBoxSize。 需要注意的是虽然只有当 BoxOptions 关心的盒模型变化时才会触发通知但实际上通知时会将三种不同盒模型下的具体大小都返回给回调函数用户无需再次手动获取。 window.resize事件能帮我们监听窗口大小的变化。但是reize事件会在一秒内触发将近60次所以很容易在改变窗口大小时导致性能问题。换句话说window.resize事件通常是浪费的因为它会监听每个元素的大小变化只有window对象才有resize事件而不是具体到某个元素的变化。如果我们只想监听某个元素的变化的话这种操作就很浪费性能了。 而ResizeObserver API就可以帮助我们监听一个DOM节点的变化这种变化包括但不仅限于 某个节点的出现和隐藏某个节点的大小变化 resize事件只有当 viewport 的大小发生变化时会被触发元素大小的变化不会触发 resize 事件并且也只有注册在 window 对象上的回调会在 resize 事件发生时被调用其他元素上的回调不会被调用。 当「resize」事件发生后我们往往需要通过调用getBoundingClientRect或者getComputedStyle来获取此时我们关心的元素大小以此判断元素是否发生了变化。频繁调用getBoundingClientRect、getComputedStyle等 API 会导致「浏览器重排reflow」导致页面性能变差 API介绍
**ResizeObserver.disconnect()**取消特定观察者目标上所有对Element的监听。**ResizeObserver.observe()**开始对指定Element的监听。 第一个参数为观察的元素。第二个参数为可选参数 BoxOptions用来指定将以哪种盒子模型来观察变动如content-box(默认值)border-box和device-pixel-content-box。 **ResizeObserver.unobserve()**结束对指定Element的监听。
第三方 --resize-observer-polyfill
栗子使用 resize-observer-polyfill 管理 DOM 变化-JavaScript中文网-JavaScript教程资源分享门户
推荐开源项目ResizeObserver Polyfill - 窗口尺寸监听解决方案-CSDN博客
举个栗子
const ro new ResizeObserver(entries {for (let entry of entries) {entry.target.style.borderRadius Math.max(0, 250 - entry.contentRect.width) px;}
});ro.observe(document.querySelector(.box));应用场景
虚拟列表支持动态高度
响应式广告投放
探索 ResizeObserver 的神奇力量ResizeObserver API 的目标是提供一种高效且准确地监听 D - 掘金
PerformanceObserver
待补充…
参考文献
探秘神奇的IntersectionObserver释放网页性能的黑科技IntersectionObserver 提供 - 掘金
交叉观察器 API - Web API | MDN
尝试使用JS IntersectionObserver让标题和导航联动 ? 张鑫旭-鑫空间-鑫生活
交叉观察器 API - Web API | MDN
JavaScript中最重要的5个Observer看这一篇就够了_js observer-CSDN博客
开启DOM观察者模式引爆你的前端开发创造力 - MutationObserverMutationObserver 的 - 掘金
MutationObserver - Web API | MDN
ResizeObserver - Web API | MDN
Resize Observer 介绍及原理浅析-resize-observer-polyfill
一个较新的WEB API——ResizeObserver 的使用今天在看同事代码的时候看见这个API出于好奇就去了解了 - 掘金
浏览器的 5 种 Observer你用过几种网页开发中我们经常要处理用户交互我们会用 addEventListen - 掘金