Appearance
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
html,
body {
height: 500%;
}
div {
width: 200px;
height: 200px;
background-color: #ddd;
margin: 0 auto;
margin-top: 1000px;
}
div img {
width: 100%;
height: 100%;
opacity: 0;
}
</style>
</head>
<body>
<!--
IntersectionObserver:异步观察目标元素与其祖先元素或视口交叉状态的方法。
优点: 方便 内置节流处理
缺点: 兼容性不好 适合移动端
-->
<div>
<img src="" alt="" data-img="./demo.png">
</div>
<div>
<img src="" alt="" data-img="./demo2.webp">
</div>
<div>
<img src="" alt="" data-img="./demo3.webp">
</div>
<script>
const containers = document.querySelectorAll('div')
const html = document.documentElement
let io = new IntersectionObserver(entries => {
// 初始化时,触发一次回调,监视的所有元素的isIntersecting: false
// 之后回调的触发只显示满足条件的元素的信息
// isIntersecting: 元素是否与视口交叉
const { isIntersecting, target } = entries[0]
const img = target.children[0]
if (isIntersecting && !img.isLoaded) {
// 如果交叉信息为true并且图片没有加载
img.src = img.dataset.img
img.style.opacity = 1
img.isLoaded = true
io.unobserve(target) // 取消观察
}
}, {
// 如果传了第二个参数
threshold: [1]
// 滚轮下滑
// 监视的每个元素完全出现在视口时,触发一次回调,isIntersecting: true
// 监视的每个元素顶部一点点离开视口时,触发一次回调,isIntersecting: false
// 滚轮上滑
// 监视的每个元素完全出现在视口时,触发一次回调,isIntersecting: true
// 监视的每个元素底部一点点离开视口时,触发一次回调,isIntersecting: false
// threshold: [0.5]
// 监视的每个元素一半出现在视口时,触发一次回调,isIntersecting: true
// 监视的每个元素一半离开视口时,触发一次回调,isIntersecting: true
// threshold: [0] 默认值
// 滚轮下滑
// 监视的每个元素顶部一点点出现在视口时,触发一次回调,isIntersecting: true
// 监视的每个元素完全离开视口时,触发一次回调,isIntersecting: false
// 滚轮上滑
// 监视的每个元素底部一点点出现在视口时,触发一次回调,isIntersecting: true
// 监视的每个元素完全离开视口时,触发一次回调,isIntersecting: false
// threshold: [0, 0.5, 1] // 只要符合上面三种情况任意之一,都会触发
})
containers.forEach(container => {
// 监视所有container与视口交叉信息
io.observe(container)
})
// 一个小问题,如果查看非首屏的图片后刷新,当前视图的图片不会显示,但isIntersecting
// 为true, 只有它消失再重新出现才会显示, 但一般刷新后滚动条都会重置到最开始,不会
// 遇到这个问题,如果非要处理的话
// let io2 = new IntersectionObserver(entries => {
// entries.forEach(entry => { // 找到交叉信息为true的容器
// if (entry.isIntersecting) {
// const { isIntersecting, target } = entry
// const img = target.children[0]
// if (isIntersecting && !img.isLoaded) {
// img.src = img.dataset.img
// img.style.opacity = 1
// img.isLoaded = true
// io.unobserve(target)
// }
// }
// })
// }, {
// threshold: [1]
// })
</script>
</body>
</html>