IntersectionObserver 在小屏幕上对长段 JS 不起作用
IntersectionObserver does not work on small screens for long sections JS
此脚本为活动部分发出活动 class。最近注意到它停止在小屏幕上工作。即使在 chrome 的开发者控制台中,我会开始增加屏幕尺寸,它会出现,一旦我开始缩小它就会立即停止工作(活动 class 消失)。但只有一个长的部分,在较短的部分一切正常。如何解决?
在代码片段中,我设置了一个很大的固定高度,所以投资组合link没有收到活动class,在我的例子中,当部分宽度增加时,它的高度减小,所以在某些时候一切都开始工作。
const links = document.querySelectorAll('.nav-link');
const sections = [... document.querySelectorAll('.forJS')];
const callback = (entries) => {
links.forEach((link) => link.classList.remove('active'));
const elem = entries.find((entry) => entry.isIntersecting);
if (elem) {
const index = sections.findIndex((section) => section === elem.target);
links[index].classList.add('active');
}
}
let observer = new IntersectionObserver(callback, {
rootMargin: '0px',
threshold: 0.5
});
sections.forEach((section) => observer.observe(section));
section {
height: 100vh;
scroll-y: auto;
}
.long{
height: 300vh;
}
.nav-link.active{
color: red;
}
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/js/bootstrap.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet"/>
<body>
<header class="fixed-top">
<nav class="navbar navbar-expand-lg navCustom">
<div class="container">
<ul class="navbar-nav justify-content-center">
<li class="nav-item">
<a class="nav-link" href="#main">Main</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#about">About us</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#portfolio">Portfolio</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#contacts">Contacts</a>
</li>
</ul>
</div>
</nav>
</header>
<section class="forJS text-center">Some info 1</section>
<section class="forJS text-center">Some info 2</section>
<section class="forJS text-center long">Some info 3</section>
<section class="text-center">Some info 4</section>
<section class="text-center">Some info 5</section>
<section class="text-center">Some info 6</section>
<section class="text-center">Some info 7</section>
<section class="text-center">Some info 8</section>
<section class="text-center">Some info 9</section>
<section class="forJS text-center">Some info 10</section>
</body>
主要问题是threshold: 0.5
。这告诉观察者一旦 50% 的元素在视口中可见就触发。对于你的“长”元素,因为它有 300vh 高,而你的视口有 100vh 高,它的最大可见度是 100vh/300vh = 33%,所以观察者永远不会开火。
为了解决这个问题,您可以将阈值调整为更小的值,例如 0.25。这将修复长部分的行为,但会使较短部分的活动 link 提前更改。所以我建议你添加 2 个观察者:1 个用于阈值为 0.5 (.forJS:not(.long)
) 的短部分,另一个用于阈值为 0.25 (.forJS.long
) 的较长部分。
const links = document.querySelectorAll('.nav-link');
const sectionsShort = [...document.querySelectorAll('.forJS:not(.long)')];
const sectionsLong = [...document.querySelectorAll('.forJS.long')];
const sections = [...document.querySelectorAll('.forJS')];
const callback = entries => {
links.forEach((link) => link.classList.remove('active'));
const elem = entries.find((entry) => entry.isIntersecting);
if (elem) {
const index = sections.findIndex((section) => section === elem.target);
links[index].classList.add('active');
}
}
const observerShort = new IntersectionObserver(callback, {
rootMargin: '0px',
threshold: .5,
});
const observerLong = new IntersectionObserver(callback, {
rootMargin: '0px',
threshold: .25,
});
sectionsShort.forEach((section) => {
observerShort.observe(section)
});
sectionsLong.forEach((section) => {
observerLong.observe(section)
});
此脚本为活动部分发出活动 class。最近注意到它停止在小屏幕上工作。即使在 chrome 的开发者控制台中,我会开始增加屏幕尺寸,它会出现,一旦我开始缩小它就会立即停止工作(活动 class 消失)。但只有一个长的部分,在较短的部分一切正常。如何解决?
在代码片段中,我设置了一个很大的固定高度,所以投资组合link没有收到活动class,在我的例子中,当部分宽度增加时,它的高度减小,所以在某些时候一切都开始工作。
const links = document.querySelectorAll('.nav-link');
const sections = [... document.querySelectorAll('.forJS')];
const callback = (entries) => {
links.forEach((link) => link.classList.remove('active'));
const elem = entries.find((entry) => entry.isIntersecting);
if (elem) {
const index = sections.findIndex((section) => section === elem.target);
links[index].classList.add('active');
}
}
let observer = new IntersectionObserver(callback, {
rootMargin: '0px',
threshold: 0.5
});
sections.forEach((section) => observer.observe(section));
section {
height: 100vh;
scroll-y: auto;
}
.long{
height: 300vh;
}
.nav-link.active{
color: red;
}
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/js/bootstrap.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet"/>
<body>
<header class="fixed-top">
<nav class="navbar navbar-expand-lg navCustom">
<div class="container">
<ul class="navbar-nav justify-content-center">
<li class="nav-item">
<a class="nav-link" href="#main">Main</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#about">About us</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#portfolio">Portfolio</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#contacts">Contacts</a>
</li>
</ul>
</div>
</nav>
</header>
<section class="forJS text-center">Some info 1</section>
<section class="forJS text-center">Some info 2</section>
<section class="forJS text-center long">Some info 3</section>
<section class="text-center">Some info 4</section>
<section class="text-center">Some info 5</section>
<section class="text-center">Some info 6</section>
<section class="text-center">Some info 7</section>
<section class="text-center">Some info 8</section>
<section class="text-center">Some info 9</section>
<section class="forJS text-center">Some info 10</section>
</body>
主要问题是threshold: 0.5
。这告诉观察者一旦 50% 的元素在视口中可见就触发。对于你的“长”元素,因为它有 300vh 高,而你的视口有 100vh 高,它的最大可见度是 100vh/300vh = 33%,所以观察者永远不会开火。
为了解决这个问题,您可以将阈值调整为更小的值,例如 0.25。这将修复长部分的行为,但会使较短部分的活动 link 提前更改。所以我建议你添加 2 个观察者:1 个用于阈值为 0.5 (.forJS:not(.long)
) 的短部分,另一个用于阈值为 0.25 (.forJS.long
) 的较长部分。
const links = document.querySelectorAll('.nav-link');
const sectionsShort = [...document.querySelectorAll('.forJS:not(.long)')];
const sectionsLong = [...document.querySelectorAll('.forJS.long')];
const sections = [...document.querySelectorAll('.forJS')];
const callback = entries => {
links.forEach((link) => link.classList.remove('active'));
const elem = entries.find((entry) => entry.isIntersecting);
if (elem) {
const index = sections.findIndex((section) => section === elem.target);
links[index].classList.add('active');
}
}
const observerShort = new IntersectionObserver(callback, {
rootMargin: '0px',
threshold: .5,
});
const observerLong = new IntersectionObserver(callback, {
rootMargin: '0px',
threshold: .25,
});
sectionsShort.forEach((section) => {
observerShort.observe(section)
});
sectionsLong.forEach((section) => {
observerLong.observe(section)
});