user15546658
user15546658

Reputation: 39

IntersectionObserver + Scroll eventListener

I'm using a mix of IntersectionObserver with a scroll eventListener. Just to explain: The function is animating a CSS variable based on scroll position.

I order to prevent the browser to fire each time I scroll, even though I'm not near the element, I'm doing to do something like this :

if (entry.isIntersecting) {
  window.addEventListener('scroll', moduleAnimation, true);
} else {
  window.removeEventListener('scroll', moduleAnimation, true);
}

I want the function moduleAnimation to listen to scroll only when the entry is intersecting. It works fine, except for the removeEventListener.

What did I do wrong? :)

Thanks a lot !

EDIT : Here's my complete feature:

    function stickyModule() {
    document.querySelectorAll('.full-module__img').forEach(function (module) {
        new IntersectionObserver((entries, observer) => {
            entries.forEach(entry => {

                let textOffset = module.parentElement.querySelector('.full-module__copy-wrapper').offsetTop;
                module.parentElement.parentElement.style.setProperty('--offsetWrapper', textOffset + "px");

                function moduleAnimation() {
                    console.log('scroll event');
                    let targetBrightness = 0.2;
                    let targetGrayscale = 1;
                    let targetContrast = 1.2;
                    let ImgDistFromTopDoc = Math.floor(module.parentElement.getBoundingClientRect().top + window.pageYOffset);
                    let toScroll = (window.pageYOffset - ImgDistFromTopDoc) / (module.offsetHeight - textOffset);
                    let scrollGrayscale = toScroll * targetGrayscale;
                    let scrollBrightness = 1 - toScroll * (1 - targetBrightness);
                    let scrollConstrast = 1 + toScroll * (targetContrast - 1);
                    if (toScroll < 0) {
                        module.style.setProperty('--grayscale', "0")
                        module.style.setProperty('--brightness', "1")
                        module.style.setProperty('--contrast', "1")
                    } else if (toScroll < 1 && toScroll > 0) {
                        module.style.setProperty('--grayscale', scrollGrayscale.toFixed(2))
                        module.style.setProperty('--brightness', scrollBrightness.toFixed(2))
                        module.style.setProperty('--contrast', scrollConstrast.toFixed(2))
                    } else if (toScroll > 1) {
                        module.style.setProperty('--grayscale', targetGrayscale)
                        module.style.setProperty('--brightness', targetBrightness)
                        module.style.setProperty('--contrast', targetContrast);
                    }
                }
                window.scrollTo(window.scrollX, window.scrollY + 1);
                window.scrollTo(window.scrollX, window.scrollY - 1);

                if (entry.isIntersecting) {
                    window.addEventListener('scroll', moduleAnimation, true);
                    window.addEventListener('resize', moduleAnimation, true);
                    console.log('if');
                }
                else{
                    window.removeEventListener('scroll', moduleAnimation, true);
                    console.log('else');
                }
            });
        }).observe(module);
    })
} 
    document.addEventListener('DOMContentLoaded', stickyModule);

I kinda new with JS sorry If my code seems crazy haha

Upvotes: 1

Views: 2259

Answers (1)

David Mann
David Mann

Reputation: 2270

You have to use the exact same function in removeEventListener that you used in addEventListener. The same definition isn't enough.

In your example, you remake moduleAnimation for every entry every time the observer fires. It looks like it's the same function, but it's a brand new one with the same name and same definition. Instead, you can move the function declaration outside of the observer's callback.

function stickyModule() {
    document.querySelectorAll('.full-module__img').forEach(function (module) {
        function moduleAnimation() {
            console.log('scroll event');
        }

        new IntersectionObserver((entries, observer) => {
            entries.forEach(entry => {
                console.log('entry', entry.isIntersecting)

                if (entry.isIntersecting) {
                    window.addEventListener('scroll', moduleAnimation, true);
                    console.log('if');
                } else {
                    window.removeEventListener('scroll', moduleAnimation, true);
                    console.log('else');
                }
                
            });
        }).observe(module);
    })
} 

document.addEventListener('DOMContentLoaded', stickyModule);
body {
    height: 200vh;
}
<img src="https://via.placeholder.com/150" alt="" class="full-module__img">

Moving it out into the loop makes it still have scope with each module, but leaves the instance the same for each time the observer fires.

Upvotes: 4

Related Questions