IntersectionObserver 不适用于小屏幕长段 JS

问题描述 投票:0回答:3

此脚本为活动部分发出活动类。最近注意到它在小屏幕上停止工作。即使在 Chrome 的开发人员控制台中,我也会开始增加屏幕尺寸,它就会出现,一旦我开始减小它就会立即停止工作(活动类消失)。但仅适用于较长的部分,在较短的部分中一切正常。如何解决这个问题?

在代码片段中,我设置了一个较大的固定高度,因此投资组合链接不会接收活动类,在我的示例中,当部分宽度增加时,其高度会减小,因此在某些时候一切都会开始工作。

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/[email protected]/dist/js/bootstrap.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/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>

javascript ecmascript-6 intersection-observer
3个回答
11
投票

主要问题是

threshold: 0.5
。这告诉观察者一旦 50% 的元素在视口中可见就触发。对于“长”元素,由于其高度为 300vh,而视口高度为 100vh,因此它的最大可见度为 100vh/300vh = 33%,因此观察者永远不会触发。

为了解决这个问题,您可以将阈值调整为较小的值,例如 0.25。这将修复长部分的行为,但它会使较短部分的活动链接提前更改。因此,我建议您添加 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)
});

0
投票

我遇到了同样的问题,最终根据视口和截面高度分别计算阈值。

对我来说,我使用了这个片段,它的效果就像一个魅力:

const viewportHeight = window.innerHeight;
sections.forEach((element) => {
    if (typeof element === "undefined" || element === null) {
        return;
    }
    const threshold = viewportHeight / element.clientHeight * 0.6; // element fills 60% of the viewport
    observers.current[key] = new IntersectionObserver(
        callback,
        {threshold}
    );
    observers.current[key].observe(element as Element);
});

-1
投票

请像下面这样更改阈值,它会起作用。

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:[.5,0] // threshold changed
});

sections.forEach((section) => observer.observe(section));
© www.soinside.com 2019 - 2024. All rights reserved.