为什么路口观察者一直在运行?

why does intersection observer keeps on running?

我想使用交集观察器更改 header 的 class。这里的想法是,我有一个具有完整高度和宽度的 header,当我们向下滚动到另一个 div 时,header 缩小为一个小条。

这是我的 javascript 代码。

if('IntersectionObserver' in window){
  const options = {
    root: null,
    rootMargin: '0px',
    threshold: 0.0
  }

  callback = (entries) => {
    const header = document.querySelector("header");
    const IS_INTERSECTING = entries[0].isIntersecting;
    if(!IS_INTERSECTING){
      header.classList.replace("header_full","header");
      return false;
    }else if(IS_INTERSECTING){
      header.classList.replace("header","header_full");
      return false;
    }else{
      return false;
    }
  }

  let observer = new IntersectionObserver(callback, options);

  let target = document.querySelector('header');
  observer.observe(target);
}

这是我的标记

<div class="application">
        <header class="header_full">
            <div>
                <img src="logo_2.png" alt="logo">
                <h2>Intersection Observer</h2>
            </div>
            <div class="bars"></div>
        </header>
        <div class="full">full_1</div>
        <div class="full">full_2</div>
        <div class="full">full_3</div>
        <div class="full">full_4</div>
        <div class="full">full_5</div>
    </div>

这是我的 scss 文件

%full{
    height: 100vh;

}
body{
    margin: unset;
    background:whitesmoke;
    font-family: Comfortaa;
}

.full{
    @extend %full;
}

.header_full{
    @extend %full;
    background: goldenrod;
    display: grid;
    place-items:center;
    position: relative;

    & img{
        height: 250px;
        width:250px;
        object-fit: contain;
    }

    & h2{
        text-align: center;
        color: rgb(60, 60, 60);
        letter-spacing: 1.4px;
    }

    & .bars{
        &::after{
            content: "☰";
            font-size:1.3rem;
        }
        height: 40px;
        width: 40px;
        display: grid;
        place-items:center;
        position:absolute;
        top:10px;
        right: 10px;
        color: rgb(60,60,60);
    }
}

header{
    transition: all 500ms linear;
}

.header{
    height: 100px;
    max-height: 100px;;
    background: goldenrod;
    position: fixed;
    top:0;
    width: 100%;
    padding: 10px;
    box-sizing: border-box;
    animation: bring_down 500ms linear;

    & img{
        height: 80px;
        width:80px;
        object-fit: contain;
    }

    & h2{
        display: none;
    }

    & .bars{
        position:static;
    }
}

我面临的问题是当我向下滚动时,路口观察器不断切换 classes 即。 header_full 和 header。让它一直闪烁。我试过“observer.unobserve(header)”,但我遇到的问题是停止观察,因此 header 仅更改一次。

我也参考了以下堆栈溢出问题,但没有成功。

Intersection Observer change class based on clientHeight

IntersectionObserver 基于视口(或另一个指定元素根)内的可见性,因此如果您的目标不断进入和退出视口,您将以无限循环告终。

这就是您的代码正在做的事情。 header 退出视口,触发 !IS_INTERSECTING 控制流,立即将其放回视口内。 Re-entering 视口触发 IS_INTERSECTING 控制流,它立即将其推出 - 这是一个无限循环。

您需要 IntersectionObserver 定位静态元素,该元素不会因回调而改变其 DOM 位置。我建议将 header 完全从文档流中取出,并在其后放置一个 100vh 占位符。就剩余内容而言,当您的 header 从 100vh 变为本质上 0px 时,移除 heavy 布局偏移的额外好处.

<div class="application">
  <div class="header_placeholder"></div>
  <header class="header_full">
      <div>
          <img src="logo_2.png" alt="logo">
          <h2>Intersection Observer</h2>
      </div>
      <div class="bars"></div>
  </header>
  <div class="full">full_1</div>
  <div class="full">full_2</div>
  <div class="full">full_3</div>
  <div class="full">full_4</div>
  <div class="full">full_5</div>
</div>
%full{
    height: 100vh;

}
body{
    margin: unset;
    background:whitesmoke;
    font-family: Comfortaa;
}

.full{
    @extend %full;
}

.header_placeholder {
  height: 100vh;
}

.header_full{
    @extend %full;
    background: goldenrod;
    display: grid;
    place-items:center;

    /* move this out of the document flow */
    position: absolute;
    top: 0;
    width: 100%;

    & img{
        height: 250px;
        width:250px;
        object-fit: contain;
    }

    & h2{
        text-align: center;
        color: rgb(60, 60, 60);
        letter-spacing: 1.4px;
    }

    & .bars{
        &::after{
            content: "☰";
            font-size:1.3rem;
        }
        height: 40px;
        width: 40px;
        display: grid;
        place-items:center;
        position:absolute;
        top:10px;
        right: 10px;
        color: rgb(60,60,60);
    }
}

header{
    transition: all 500ms linear;
}

.header{
    height: 100px;
    max-height: 100px;;
    background: goldenrod;
    position: fixed;
    top:0;
    width: 100%;
    padding: 10px;
    box-sizing: border-box;
    animation: bring_down 500ms linear;

    & img{
        height: 80px;
        width:80px;
        object-fit: contain;
    }

    & h2{
        display: none;
    }

    & .bars{
        position:static;
    }
}
if('IntersectionObserver' in window){
  const options = {
    root: null,
    rootMargin: '0px',
    threshold: 0.0
  }

  callback = (entries) => {
    const header = document.querySelector("header");
    const IS_INTERSECTING = entries[0].isIntersecting;
    if(!IS_INTERSECTING){
      header.classList.replace("header_full","header");
      return false;
    }else if(IS_INTERSECTING){
      header.classList.replace("header","header_full");
      return false;
    }else{
      return false;
    }
  }

  let observer = new IntersectionObserver(callback, options);

  // target the placeholder element here
  let target = document.querySelector('.header_placeholder');
  observer.observe(target);
}