使用 IntersectionObserver 在元素完全通过阈值后触发事件
Use IntersectionObserver To Trigger Event AFTER Element Completely Passes Threshold
我有一些 IntersectionObserver
的设置。 observer
切换要在用户向下滚动页面时制作的新框。 lastBoxObserver
在持续滚动时加载新框。
我想做的是在框离开第一个观察者中设置的阈值(observer
- 其阈值设置为 1
)后更改框的颜色。因此,一旦方框 12 进入视口,它就会通过观察者,一旦它完全超出该观察者的阈值并且方框 13 进入观察者,方框 12 的背景可能会从绿色变为橙色。
有没有办法做到这一点?也许通过添加额外的观察者,或向 observer
添加代码?非常感谢任何帮助。
代码笔:https://codepen.io/jon424/pen/NWwReEJ
JavaScript
const boxes = document.querySelectorAll(".box");
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
entry.target.classList.toggle("show", entry.isIntersecting);
if (entry.isIntersecting) observer.unobserve(entry.target);
});
},
{
threshold: 1,
}
);
const lastBoxObserver = new IntersectionObserver((entries) => {
const lastBox = entries[0];
if (!lastBox.isIntersecting) return;
loadNewBoxes();
lastBoxObserver.unobserve(lastBox.target);
lastBoxObserver.observe(document.querySelector(".box:last-child"));
}, {});
lastBoxObserver.observe(document.querySelector(".box:last-child"));
boxes.forEach((box) => {
observer.observe(box);
});
const boxContainer = document.querySelector(".container");
function loadNewBoxes() {
for (let i = 0; i < 1000; i++) {
const box = document.createElement("div");
box.textContent = `${i + 1}`;
box.classList.add("box");
observer.observe(box);
boxContainer.appendChild(box);
}
}
HTML
<div class="container">
<div class="box">0</div>
</div>
CSS
.container {
display: flex;
flex-direction: column;
gap: 1rem;
align-items: flex-start;
}
.box {
background: green;
color: white;
font-size: 4rem;
text-align: center;
margin: auto;
height: 100px;
width: 100px;
border: 1px solid black;
border-radius: 0.25rem;
padding: 0.5rem;
transform: translateX(100px);
opacity: 0;
transition: 150ms;
}
.box.show {
transform: translateX(0);
opacity: 1;
}
.box.show.more {
background-color: orange;
}
你只需要在你的第一个观察者中添加颜色变化逻辑。
我对您的代码进行了以下更改进行了测试,
在 css 中,将 .box.show.more 更改为 -
.box.more {
background-color: orange;
}
在javascript-
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
entry.target.classList.toggle("show", entry.isIntersecting);
if (entry.isIntersecting) {
observer.unobserve(entry.target);
if(entry.target.textContent === '13')
entry.target.previousSibling.classList.toggle('more');
}
});
},
{
threshold: 1,
}
);
如您所见,唯一的变化是我添加了这部分-
if(entry.target.textContent === '13')
entry.target.previousSibling.classList.toggle('more');
为了便于测试,我还更改了新 div 的数量,从 1000 增加到 20。
如果您想在框 13 进入视口后立即更改框 12 的颜色,只需将“阈值”从 1 更改为 0。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<style>
.container {
display: flex;
flex-direction: column;
gap: 1rem;
align-items: flex-start;
}
.box {
background: green;
color: white;
font-size: 4rem;
text-align: center;
margin: auto;
height: 100px;
width: 100px;
border: 1px solid black;
border-radius: 0.25rem;
padding: 0.5rem;
opacity: 0;
}
.box.show {
opacity: 1;
}
.box.show.more {
background-color: orange;
}
.mytest{
border:solid 10px #000;
background-color: orange;
}
</style>
<div class="container">
<div class="box">0</div>
<div class="sentinel"></div>
</div>
<script>
/* */
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("show");
}
if (entry.boundingClientRect.top < entry.rootBounds.top) {
/* entry is above viewport */
entry.target.classList.add("mytest");
observer.unobserve(entry.target);
}
});
},
{
threshold: 0, /* top is 200 below top of viewport - something for the box to scroll into*/
rootMargin: "-200px 0px 0px 0px"
}
);
/* last div sentinel indicates last box */
const mysentinel = new IntersectionObserver((entries) => {
var entry = entries[0];
if (entry.isIntersecting) {
loadNewBoxes();
}
},{
threshold: 0
});
const boxContainer = document.querySelector(".container");
const sentinel = document.querySelector(".sentinel");
/* setup - create extra boxes, sentinel is last after boxes */
loadNewBoxes();
mysentinel.observe(sentinel);
function loadNewBoxes() {
for (let i = 0; i < 10; i++) {
const box = document.createElement("div");
box.textContent = `${i + 1}`;
box.classList.add("box");
box.classList.add("show");
observer.observe(box);
boxContainer.appendChild(box);
}
boxContainer.appendChild(sentinel);
}
</script>
</body>
</html>
IntersectionObserver 回调是异步的,如果你滚动得足够快,那么一些框会被遗漏。我已经简化了你的代码。如果 box/observed 目标在根顶部之上,那么我添加一个 class 并取消观察它。如果框正在转换,我添加一个 class 来显示框。我使用 sentinel 来指示最后一个框,并在 sentinel 到达视口时添加更多框。
我有一些 IntersectionObserver
的设置。 observer
切换要在用户向下滚动页面时制作的新框。 lastBoxObserver
在持续滚动时加载新框。
我想做的是在框离开第一个观察者中设置的阈值(observer
- 其阈值设置为 1
)后更改框的颜色。因此,一旦方框 12 进入视口,它就会通过观察者,一旦它完全超出该观察者的阈值并且方框 13 进入观察者,方框 12 的背景可能会从绿色变为橙色。
有没有办法做到这一点?也许通过添加额外的观察者,或向 observer
添加代码?非常感谢任何帮助。
代码笔:https://codepen.io/jon424/pen/NWwReEJ
JavaScript
const boxes = document.querySelectorAll(".box");
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
entry.target.classList.toggle("show", entry.isIntersecting);
if (entry.isIntersecting) observer.unobserve(entry.target);
});
},
{
threshold: 1,
}
);
const lastBoxObserver = new IntersectionObserver((entries) => {
const lastBox = entries[0];
if (!lastBox.isIntersecting) return;
loadNewBoxes();
lastBoxObserver.unobserve(lastBox.target);
lastBoxObserver.observe(document.querySelector(".box:last-child"));
}, {});
lastBoxObserver.observe(document.querySelector(".box:last-child"));
boxes.forEach((box) => {
observer.observe(box);
});
const boxContainer = document.querySelector(".container");
function loadNewBoxes() {
for (let i = 0; i < 1000; i++) {
const box = document.createElement("div");
box.textContent = `${i + 1}`;
box.classList.add("box");
observer.observe(box);
boxContainer.appendChild(box);
}
}
HTML
<div class="container">
<div class="box">0</div>
</div>
CSS
.container {
display: flex;
flex-direction: column;
gap: 1rem;
align-items: flex-start;
}
.box {
background: green;
color: white;
font-size: 4rem;
text-align: center;
margin: auto;
height: 100px;
width: 100px;
border: 1px solid black;
border-radius: 0.25rem;
padding: 0.5rem;
transform: translateX(100px);
opacity: 0;
transition: 150ms;
}
.box.show {
transform: translateX(0);
opacity: 1;
}
.box.show.more {
background-color: orange;
}
你只需要在你的第一个观察者中添加颜色变化逻辑。
我对您的代码进行了以下更改进行了测试,
在 css 中,将 .box.show.more 更改为 -
.box.more {
background-color: orange;
}
在javascript-
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
entry.target.classList.toggle("show", entry.isIntersecting);
if (entry.isIntersecting) {
observer.unobserve(entry.target);
if(entry.target.textContent === '13')
entry.target.previousSibling.classList.toggle('more');
}
});
},
{
threshold: 1,
}
);
如您所见,唯一的变化是我添加了这部分-
if(entry.target.textContent === '13')
entry.target.previousSibling.classList.toggle('more');
为了便于测试,我还更改了新 div 的数量,从 1000 增加到 20。
如果您想在框 13 进入视口后立即更改框 12 的颜色,只需将“阈值”从 1 更改为 0。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<style>
.container {
display: flex;
flex-direction: column;
gap: 1rem;
align-items: flex-start;
}
.box {
background: green;
color: white;
font-size: 4rem;
text-align: center;
margin: auto;
height: 100px;
width: 100px;
border: 1px solid black;
border-radius: 0.25rem;
padding: 0.5rem;
opacity: 0;
}
.box.show {
opacity: 1;
}
.box.show.more {
background-color: orange;
}
.mytest{
border:solid 10px #000;
background-color: orange;
}
</style>
<div class="container">
<div class="box">0</div>
<div class="sentinel"></div>
</div>
<script>
/* */
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("show");
}
if (entry.boundingClientRect.top < entry.rootBounds.top) {
/* entry is above viewport */
entry.target.classList.add("mytest");
observer.unobserve(entry.target);
}
});
},
{
threshold: 0, /* top is 200 below top of viewport - something for the box to scroll into*/
rootMargin: "-200px 0px 0px 0px"
}
);
/* last div sentinel indicates last box */
const mysentinel = new IntersectionObserver((entries) => {
var entry = entries[0];
if (entry.isIntersecting) {
loadNewBoxes();
}
},{
threshold: 0
});
const boxContainer = document.querySelector(".container");
const sentinel = document.querySelector(".sentinel");
/* setup - create extra boxes, sentinel is last after boxes */
loadNewBoxes();
mysentinel.observe(sentinel);
function loadNewBoxes() {
for (let i = 0; i < 10; i++) {
const box = document.createElement("div");
box.textContent = `${i + 1}`;
box.classList.add("box");
box.classList.add("show");
observer.observe(box);
boxContainer.appendChild(box);
}
boxContainer.appendChild(sentinel);
}
</script>
</body>
</html>
IntersectionObserver 回调是异步的,如果你滚动得足够快,那么一些框会被遗漏。我已经简化了你的代码。如果 box/observed 目标在根顶部之上,那么我添加一个 class 并取消观察它。如果框正在转换,我添加一个 class 来显示框。我使用 sentinel 来指示最后一个框,并在 sentinel 到达视口时添加更多框。