How to remove scroll event listener?
Asked Answered
C

3

12

I am trying to remove scroll event listener when I scroll to some element. What I am trying to do is call a click event when some elements are in a viewport. The problem is that the click event keeps calling all the time or after first call not at all. (Sorry - difficult to explain) and I would like to remove the scroll event to stop calling the click function.

My code:

   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}%)`;
        }
    });
Chutney answered 18/1, 2019 at 13:12 Comment(2)
Y
25

You can only remove event listeners on external functions. You cannot remove event listeners on anonymous functions, like you have used.

Replace this code

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

and do this instead

window.addEventListener('scroll', someFunction);

Then move your function logic into the function

function someFunction() {
  // add logic here
}

You can then remove the click listener when some condition is met i.e. when the element is in the viewport

window.removeEventListener('scroll', someFunction);
Ylla answered 18/1, 2019 at 13:28 Comment(0)
W
7

Instead of listening to scroll event you should try using Intersection Observer (IO) Listening to scroll event and calculating the position of elements on each scroll can be bad for performance. With IO you can use a callback function whenever two elements on the page are intersecting with each other or intersecting with the viewport.

To use IO you first have to specify the options for IO. Since you want to check if your element is in view, leave the root element out.

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

let observer = new IntersectionObserver(callback, options);

Then you specify which elements you want to watch:

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

Lastly you have to define what should happen once the element is in the viewport:

let callback = (entries, observer) => { 
  entries.forEach(entry => {
    // Each entry describes an intersection change for one observed
    // target element:
  });
};

You can also unobserve an element if you don't need the observer anymore.

Check this polyfill from w3c to support older browsers.

Wholism answered 17/9, 2019 at 9:9 Comment(0)
H
0

Here is my scenario/code, call removeEventListener as return() in the useEffect hook.

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

  React.useEffect(() => {
    if (showDrawer) {
      window.addEventListener("scroll", detectPageScroll);
    }
    return () => {
      window.removeEventListener("scroll", detectPageScroll);
    };
  }, [showDrawer]);
Heiser answered 4/4, 2022 at 21:48 Comment(1)
Even for that scenario, using Intersection Observer should be the tool of choice to use :)Wholism

© 2022 - 2024 — McMap. All rights reserved.