【问题标题】:How to delay intersection observer API如何延迟交叉口观察者 API
【发布时间】:2023-04-06 17:18:01
【问题描述】:

情况

我在页面顶部有一个固定的导航栏。当您向下滚动浏览页面的不同部分时,导航栏会动态更新(下划线和突出显示)。您也可以单击导航栏上的某个部分,它会向下滚动到该部分。

这是使用交叉点观察者 API 来检测它所在的部分并使用 scrollIntoView 滚动到每个部分来完成的。

问题

假设您在第 1 部分,然后单击最后一个部分 5,它会将页面向下滚动到中间的所有其他部分。滚动速度很快,并且当它滚动时,交叉点观察器会检测到所有部分,因此会更新导航。当每个导航项经过每个相应的部分时,您最终会获得导航快速变化的效果。

目标

如果该部分仅在帧中一毫秒,您如何延迟交叉点观察者触发菜单更改?快速滚动时,导航栏应仅在滚动停止某个部分后更新。

代码设置

const sectionItemOptions = {
  threshold: 0.7,
};

const sectionItemObserver = new IntersectionObserver((entries, observer) => {
  entries.forEach((entry) => {

    if (entry.isIntersecting) {
      // select navigation link corresponding to section

    } else {
      // deselect navigation link corresponding to section

    }
  });
}, sectionItemOptions);

// start observing all sections on page
sections.forEach((section) => {
  sectionItemObserver.observe(section);
});

想法

我的第一个想法是设置一个 setTimeout 以便导航在超时完成之前不会改变,然后如果该部分在超时完成之前离开屏幕,则取消超时。但是由于超时在 forEach 循环中,这不起作用。

const sectionItemObserver = new IntersectionObserver((entries, observer) => {
  entries.forEach((entry) => {

    let selectNavTimeout

    if (entry.isIntersecting) {

      // Set timeout when section is scrolled past
      selectNavTimeout = setTimeout(() => {
        // select navigation link corresponding to section
      }, 1000)

    } else {
      // deselect navigation link corresponding to section
      // cancel timeout when section has left screen
      clearTimeout(selectNavTimeout)
    }
  });
}, sectionItemOptions);

任何其他想法将不胜感激!谢谢:)

【问题讨论】:

    标签: javascript settimeout intersection-observer


    【解决方案1】:

    我遇到了同样的问题。我最终使用setTimeout 方法。您需要将超时与入口目标相关联,前提是每个入口目标都有一些唯一的 ID。例如,假设我们正在与具有id 属性的节点相交:

        let timeouts = {};
        const observer = new IntersectionObserver((entries, ob) => {
            for (const e of entries) {
                if (e.isIntersecting) {
                    timeouts[e.target.id] = setTimeout(() => {
                        ob.unobserve(e.target)
    
                        // handling
    
                    }, 1000)  // delay for 1 second
                } else {
                    clearTimeout(timeouts[e.target.id])
                }
            }
        }, options)
    

    【讨论】:

      【解决方案2】:

      遇到了同样的问题。根据这篇文章:https://web.dev/intersectionobserver-v2/,观察者 v2 允许您在观察者选项中设置延迟。在我的导航菜单情况下,延迟就像一个魅力:

      const observer = new IntersectionObserver((changes) => {
        for (const change of changes) {
          // ⚠️ Feature detection
          if (typeof change.isVisible === 'undefined') {
            // The browser doesn't support Intersection Observer v2, falling back to v1 behavior.
            change.isVisible = true;
          }
          if (change.isIntersecting && change.isVisible) {
            visibleSince = change.time;
          } else {
            visibleSince = 0;
          }
        }
      }, {
        threshold: [1.0],
        // ? Track the actual visibility of the element
        trackVisibility: true,
        // ? =====ANSWER=====: Set a minimum delay between notifications
        delay: 100
      }));
      

      【讨论】:

        【解决方案3】:

        经过大量头脑风暴后,我想出了一个想法,虽然不能完全回答延迟 Intersection Observer API 的问题,但它确实解决了导航栏闪烁的问题。

        导航项的突出显示是通过在其上添加“is-active”类然后对其应用 CSS 来完成的。因为“is-active”类仅在导航项上出现一瞬间,您可以使用 CSS 关键帧来延迟 CSS 样式的应用。到延迟完成时,导航项上不存在“is-active”类,并且没有更改任何样式。

        保持原来的 JS 不变,这是使用的 CSS

        .is-active {
          animation: navItemSelected;
          animation-duration: 0.3s;
          // delay longer than the time nav item is in frame
          animation-delay: 0.1s;
          // fill mode to hold animation at the end
          animation-fill-mode: forwards;
        }
        
        @keyframes navItemSelected {
          // default non-selected style of nav item
          from {
            font-style: normal;
            opacity: 0.5;
          }
          // highlighted style of nav item
          to {
            font-style: italic;
            opacity: 1;
          }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-11-22
          • 2022-01-18
          • 2021-06-26
          • 2022-01-23
          • 1970-01-01
          • 2022-01-17
          • 1970-01-01
          相关资源
          最近更新 更多