如何移除滚动事件监听器?

12

我试图在滚动到某个元素时删除滚动事件监听器。我想做的是当一些元素在视口中时调用点击事件。问题是,点击事件一直在调用,或者在第一次调用后根本不调用。(对不起 - 很难解释)我想删除滚动事件以停止调用点击函数。

我的代码:

   window.addEventListener('scroll', () => {
   window.onscroll = slideMenu;

        // offsetTop - the distance of the current element relative to the top;
        if (window.scrollY > elementTarget.offsetTop) {
            const scrolledPx = (window.scrollY - elementTarget.offsetTop);

            // going forward one step
            if (scrolledPx < viewportHeight) {
                // console.log('section one');
                const link = document.getElementById('2');
                if (link.stopclik === undefined) {
                    link.click();
                    link.stopclik = true;
                }
            }

            // SECOND STEP
            if (viewportHeight < scrolledPx && (viewportHeight * 2) > scrolledPx) {
                console.log('section two');

                // Initial state
                let scrollPos = 0;
                window.addEventListener('scroll', () => {
                    if ((document.body.getBoundingClientRect()).top > scrollPos) { // UP
                        const link1 = document.getElementById('1');
                        link1.stopclik = undefined;
                        if (link1.stopclik === undefined) {
                            link1.click();
                            link1.stopclik = true;
                        }
                    } else {
                        console.log('down');
                    }
                    // saves the new position for iteration.
                    scrollPos = (document.body.getBoundingClientRect()).top;
                });
            }

            if ((viewportHeight * 2) < scrolledPx && (viewportHeight * 3) > scrolledPx) {
                console.log('section three');
            }

            const moveInPercent = scrolledPx / base;
            const move = -1 * (moveInPercent);

            innerWrapper.style.transform = `translate(${move}%)`;
        }
    });

2
你尝试过吗:https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/removeEventListener - Ramil Amparo
此外 - 虽然超出了问题的范围 - 建议对滚动事件进行节流,因为它们可能以高速触发。 - Saraband
3个回答

25

您只能从外部函数中删除事件侦听器。无法删除匿名函数上的事件侦听器,就像您使用的那样。

替换此代码

window.addEventListener('scroll', () => { ... };

改为执行这个操作。

window.addEventListener('scroll', someFunction);

然后将您的函数逻辑移入函数中

function someFunction() {
  // add logic here
}

当满足某些条件时,即元素在视口中时,您可以删除单击监听器。

window.removeEventListener('scroll', someFunction);

7

与其监听滚动事件,您应该尝试使用Intersection Observer(IO)。在每次滚动中计算元素位置可能会影响性能。使用IO,您可以在页面上的两个元素相交或与视口相交时使用回调函数。

要使用IO,您首先必须指定IO的选项。由于您想检查元素是否在视图中,请将root元素排除在外。

let options = {
  rootMargin: '0px',
  threshold: 1.0
}

let observer = new IntersectionObserver(callback, options);

接下来您需要指定希望监视的元素:

let target = slideMenu; //document.querySelector('#oneElement') or document.querySelectorAll('.multiple-elements')
observer.observe(target); // if you have multiple elements, loop through them to add observer

最后,您需要定义元素在视口中时应发生的事件:
let callback = (entries, observer) => { 
  entries.forEach(entry => {
    // Each entry describes an intersection change for one observed
    // target element:
  });
};

如果您不再需要观察器,您还可以取消观察一个元素

请查看来自W3C的此polyfill以支持旧版浏览器。


0

这是我的场景/代码,在 useEffect 钩子中将 removeEventListener 作为 return() 调用。

  const detectPageScroll = () => {
    if (window.pageYOffset > YOFFSET && showDrawer) {
      // do something
    }
  };

  React.useEffect(() => {
    if (showDrawer) {
      window.addEventListener("scroll", detectPageScroll);
    }
    return () => {
      window.removeEventListener("scroll", detectPageScroll);
    };
  }, [showDrawer]);

即使在这种情况下,使用Intersection Observer也应该是首选的工具 :) - cloned

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接