首页 > 解决方案 > 为什么交叉口观察者一直在运行?

问题描述

我想使用交叉点观察器更改标题的类。这里的想法是我有一个完整的高度和宽度的标题,当我们向下滚动到另一个 div 时,标题会缩小到一个小条。

这是我的 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: "☰&quot;;
            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;
    }
}

我面临的问题是当我向下滚动时,交叉点观察者不断切换类,即。header_full 和标题。让它一直闪烁。我试过“observer.unobserve(header)”,但我得到的问题是停止观察,因此只改变了一次标题。

我还提到了以下堆栈溢出问题,但没有运气。

使用 Intersection Observer (IO) 更改样式标题/导航

基于 clientHeight 的 Intersection Observer 更改类

标签: javascriptintersection-observer

解决方案


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

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

您需要IntersectionObserver定位一个不会因回调而改变其 DOM 位置的静态元素。我建议您完全退出文档流程并在其后面header放置一个占位符。100vh这有一个额外的好处,即当您的标题从到基本上就剩余内容而言时,消除了繁重的布局转换。100vh0px

<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: "☰&quot;;
            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);
}

推荐阅读