ResizeObserver
介绍
ResizeObserver
是一个 Web API,用于监听元素的大小变化。它可以观察一个或多个元素的尺寸改变,并在尺寸变化时触发回调函数。使用 ResizeObserver
,您可以监测元素的宽度、高度或者它们的任意变化,而不需要轮询或使用其他复杂的解决方案。
案例
比如在开发h5的时候需要对屏幕是横屏还是竖屏进行监听
js
const target = document.querySelector('body');
const observer = new ResizeObserver(entries => {
for (let entry of entries) {
const { width, height } = entry.contentRect;
if (width < height) {
// 屏幕从横屏变为竖屏
// 执行逻辑处理
} else {
// 屏幕从竖屏变为横屏
// 执行逻辑处理
}
}
});
// 启动观察
observer.observe(target);
// 停止观察
observer.unobserve(target);
getBoundingClientRect
介绍
getBoundingClientRect
是一个 DOM API,用于获取元素的大小和位置信息。它返回一个 DOMRect
对象,包含了元素的位置、宽度、高度和其他相关属性。
示例
比如图片懒加载的原理
js
window.addEventListener('scroll', () => {
const lazyImages = document.querySelectorAll('.lazy-image');
for (let i = 0; i < lazyImages.length; i++) {
const image = lazyImages[i];
if (isInViewport(image)) {
image.src = image.dataset.src;
image.classList.remove('lazy-image');
}
}
});
function isInViewport(element) {
const rect = element.getBoundingClientRect();
return (
rect.top < (window.innerHeight || documentElement.clientHeight)
);
}
IntersectionObserver
介绍
IntersectionObserver
是一个JavaScript API,用于异步检测目标元素与其祖先或视窗之间的交叉状态。它提供了一种有效的方法来监听元素是否进入或离开视窗,或者与其祖先元素相交的程度。这对于实现懒加载、无限滚动、元素可见性等功能非常有用。
示例
实现一个简单的传送门的效果,类似于vue3的Teleport,在我们看b站视频的时候,下拉看评论的时候,会看到右下角会出现一个小的弹窗同步我们看视频的效果。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Video Portal</title>
<style>
#video {
width: 250px;
height: auto;
}
#portal {
display: none;
position: fixed;
bottom: 20px;
right: 20px;
width: 250px;
height: auto;
background-color: rgba(0, 0, 0, 0.7);
color: #fff;
padding: 20px;
text-align: center;
cursor: pointer;
}
</style>
</head>
<body>
<h1>Video Portal</h1>
<div id="v-box">
<video id="video" src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm" controls></video>
</div>
<div style="height: 1000px;width: 100%;"></div>
<div id="portal"></div>
<script>
// 创建 IntersectionObserver 实例
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
hidePortal();
} else {
showPortal();
}
});
});
// 获取视频元素和传送门元素
const video = document.getElementById('video');
const portal = document.getElementById('portal');
const vBox = document.getElementById('v-box');
document.addEventListener('scroll', function () {
// 观察视频元素
observer.observe(vBox);
})
// 停止观察
// observer.unobserve(vBox)
// 显示传送门
function showPortal() {
portal.appendChild(video)
portal.style.display = 'block'
}
// 隐藏传送门
function hidePortal() {
vBox.appendChild(video)
portal.style.display = 'none'
}
</script>
</body>
</html>
requestAnimationFrame
介绍
requestAnimationFrame
是一个用于优化动画和渲染性能的JavaScript方法。它是浏览器提供的一个API,用于在下一次浏览器重绘之前调用指定的回调函数。
使用requestAnimationFrame
来执行动画和其他需要频繁更新的操作比使用传统的setTimeout
或setInterval
方法更有效,原因如下:
requestAnimationFrame
会在浏览器准备好进行重绘时触发回调函数,通常是每秒60次,以匹配大多数显示器的刷新频率。这样可以避免在不必要的时候进行重绘,提高性能和电池寿命。- 当页面处于非激活状态时,
requestAnimationFrame
会暂停,避免不必要的计算和功耗。
示例
实现一个可以暂停和继续加载的进度条动画,通过切换浏览器的窗口可以发现进度条会暂停,切换回去之后又重新加载,非常的智能。
html
<!DOCTYPE html>
<html>
<head>
<title>Loading Progress Bar Example</title>
<style>
.progress-bar-container {
width: 100%;
height: 20px;
background-color: #ddd;
}
.progress-bar {
height: 100%;
background-color: #007bff;
width: 0;
transition: width 0.5s;
}
#start-button {
margin-top: 10px;
}
</style>
</head>
<body>
<div class="progress-bar-container">
<div class="progress-bar"></div>
</div>
当前进度:<span id="number"></span>
<button id="start-button">开始加载</button>
<button id="stop-button">暂停</button>
<script>
const startButton = document.getElementById('start-button');
const progressBar = document.querySelector('.progress-bar');
const progressNum = document.getElementById('number');
const stopButton = document.getElementById('stop-button');
let tag = true
let width = 0;
startButton.addEventListener('click', () => {
function animate() {
if ( tag && width < 100) {
width++;
progressBar.style.width = width + '%';
progressNum.innerHTML = width + '%';
requestAnimationFrame(animate);
}
}
animate();
});
stopButton.addEventListener('click', () => {
if(tag){
tag = false
stopButton.innerHTML = '暂停'
} else {
tag = true
stopButton.innerHTML = '继续';
startButton.click();
}
})
</script>
</body>
</html>
总结
上面这些方法我只是浅尝辄止的说明了下,但是无论是日常开发还是性能优化都十分有用,不仅仅是了解,我们应该更多的实践让我们的开发方式更加灵活,做到有的放矢,优雅的开发起来。