2021-11-16 , 3388 , 104 , 107
[编按: 转载于 思否网 / lzg9527, 2021-11-11. 原标题:这几个高级前端常用的API,你用到了吗?。]
本文在github做了收录 https://github.com/Michael-lz...
MutationObserver
MutationObserver 是一个可以监听 DOM 结构变化的接口。当 DOM 对象树发生任何变动时,MutationObserver 会得到通知。
API
MutationObserver 是一个构造器,接受一个 callback 参数,用来处理节点变化的回调函数,返回两个参数:
mutations:节点变化记录列表(sequence<MutationRecord>)
observer:构造 MutationObserver 对象。
MutationObserver 对象有三个方法,分别如下:
observe:设置观察目标,接受两个参数,target:观察目标,options:通过对象成员来设置观察选项
disconnect:阻止观察者观察任何改变
takeRecords:清空记录队列并返回里面的内容
//选择一个需要观察的节点var targetNode = document.getElementById('root')// 设置observer的配置选项var config = { attributes: true, childList: true, subtree: true }// 当节点发生变化时的需要执行的函数var callback = function (mutationsList, observer) { for (var 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.')
}
}
}// 创建一个observer示例与回调函数相关联var observer = new MutationObserver(callback)//使用配置文件对目标节点进行观测observer.observe(targetNode, config)// 停止观测observer.disconnect()
observe 方法中 options 参数有已下几个选项:
childList:设置 true,表示观察目标子节点的变化,比如添加或者删除目标子节点,不包括修改子节点以及子节点后代的变化
attributes:设置 true,表示观察目标属性的改变
characterData:设置 true,表示观察目标数据的改变
subtree:设置为 true,目标以及目标的后代改变都会观察
attributeOldValue:如果属性为 true 或者省略,则相当于设置为 true,表示需要记录改变前的目标属性值,设置了 attributeOldValue 可以省略 attributes 设置
characterDataOldValue:如果 characterData 为 true 或省略,则相当于设置为 true,表示需要记录改变之前的目标数据,设置了 characterDataOldValue 可以省略 characterData 设置
attributeFilter:如果不是所有的属性改变都需要被观察,并且 attributes 设置为 true 或者被忽略,那么设置一个需要观察的属性本地名称(不需要命名空间)的列表
特点
MutationObserver 有以下特点:
它等待所有脚本任务完成后才会运行,即采用异步方式
它把 DOM 变动记录封装成一个数组进行处理,而不是一条条地个别处理 DOM 变动。
它即可以观察发生在 DOM 节点的所有变动,也可以观察某一类变动
当 DOM 发生变动会触发 MutationObserver 事件。但是,它与事件有一个本质不同:事件是同步触发,也就是说 DOM 发生变动立刻会触发相应的事件;MutationObserver 则是异步触发,DOM 发生变动以后,并不会马上触发,而是要等到当前所有 DOM 操作都结束后才触发。
举例来说,如果在文档中连续插入 1000 个段落(p 元素),会连续触发 1000 个插入事件,执行每个事件的回调函数,这很可能造成浏览器的卡顿;而 MutationObserver 完全不同,只在 1000 个段落都插入结束后才会触发,而且只触发一次,这样较少了 DOM 的频繁变动,大大有利于性能。
----
IntersectionObserver
网页开发时,常常需要了解某个元素是否进入了"视口"(viewport),即用户能不能看到它。
传统的实现方法是,监听到 scroll 事件后,调用目标元素的 getBoundingClientRect()方法,得到它对应于视口左上角的坐标,再判断是否在视口之内。这种方法的缺点是,由于 scroll 事件密集发生,计算量很大,容易造成性能问题。
目前有一个新的 IntersectionObserver API,可以自动"观察"元素是否可见,Chrome 51+ 已经支持。由于可见(visible)的本质是,目标元素与视口产生一个交叉区,所以这个 API 叫做"交叉观察器"。
API
IntersectionObserver 是浏览器原生提供的构造函数,接受两个参数:callback 是可见性变化时的回调函数,option 是配置对象(该参数可选)。
var io = new IntersectionObserver(callback, option)// 开始观察io.observe(document.getElementById('example'))// 停止观察io.unobserve(element)// 关闭观察器io.disconnect()
如果要观察多个节点,就要多次调用这个方法。
io.observe(elementA)
io.observe(elementB)
目标元素的可见性变化时,就会调用观察器的回调函数 callback。callback 一般会触发两次。一次是目标元素刚刚进入视口(开始可见),另一次是完全离开视口(开始不可见)。
var io = new IntersectionObserver((entries) => { console.log(entries)
})
callback 函数的参数(entries)是一个数组,每个成员都是一个 IntersectionObserverEntry 对象。举例来说,如果同时有两个被观察的对象的可见性发生变化,entries 数组就会有两个成员。
time:可见性发生变化的时间,是一个高精度时间戳,单位为毫秒
target:被观察的目标元素,是一个 DOM 节点对象
isIntersecting: 目标是否可见
rootBounds:根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回 null
boundingClientRect:目标元素的矩形区域的信息
intersectionRect:目标元素与视口(或根元素)的交叉区域的信息
intersectionRatio:目标元素的可见比例,即 intersectionRect 占 boundingClientRect 的比例,完全可见时为 1,完全不可见时小于等于 0
举个例子
<meta charset="UTF-8" />
<title>Document</title>
<style>
#div1 { position: sticky; top: 0; height: 50px; line-height: 50px; text-align: center; background: black; color: #ffffff; font-size: 18px;
} </style>
<div id="div1">首页</div>
<div style="height: 1000px;"></div>
<div id="div2" style="height: 100px; background: red;"></div>
<script>
var div2 = document.getElementById('div2') let observer = new IntersectionObserver( function (entries) {
entries.forEach(function (element, index) { console.log(element) if (element.isIntersecting) {
div1.innerText = '我出来了'
} else {
div1.innerText = '首页'
}
})
},
{ root: null, threshold: [0, 1]
}
)
observer.observe(div2) </script>
UfqiLong
相比于 getBoundingClientRect,它的优点是不会引起重绘回流。兼容性如下
图片懒加载
图片懒加载的原理主要是判断当前图片是否到了可视区域这一核心逻辑实现的。这样可以节省带宽,提高网页性能。传统的突破懒加载是通过监听 scroll 事件实现的,但是 scroll 事件会在很短的时间内触发很多次,严重影响页面性能。为提高页面性能,我们可以使用 IntersectionObserver 来实现图片懒加载。
const imgs = document.querySelectorAll('img[data-src]')const config = { rootMargin: '0px', threshold: 0}let observer = new IntersectionObserver((entries, self) => {
entries.forEach((entry) => { if (entry.isIntersecting) { let img = entry.target
let src = img.dataset.src
if (src) {
img.src = src
img.removeAttribute('data-src')
} // 解除观察
self.unobserve(entry.target)
}
})
}, config)
imgs.forEach((image) => {
observer.observe(image)
})
无限滚动
无限滚动(infinite scroll)的实现也很简单。
var intersectionObserver = new IntersectionObserver(function (entries) { // 如果不可见,就返回
if (entries[0].intersectionRatio <= 0) return
loadItems(10) console.log('Loaded new items')
})// 开始观察intersectionObserver.observe(document.querySelector('.scrollerFooter'))
🔗 连载目录
🤖 智能推荐