简体   繁体   中英

How can I combine multiple scroll event listeners into one?

I have the following function that zooms out on images after they enter the viewport. Right now it's attaching as many event listeners as there are elements. For performance reasons I'd like to combine these into one event listener for all elements, but I don't know how. Here is my code:

HTML

<div class="image-wrapper"> 
    <div class="image-container elem-1">
        <div class="zoom-images">
            <img class="zoom" src="test" alt="test">
        </div>
    </div>
    <div class="image-container elem-2">
        <div class="zoom-images">
            <img class="zoom" src="test" alt="test">
        </div>
    </div>
    <div class="image-container elem-3">
        <div class="zoom-images">
            <img class="zoom" src="test" alt="test">
        </div>
    </div>
</div>

JAVASCRIPT

$('.zoom').each(function() {
    var el = $(this);
    var inViewport = false;
    var isZooming = false;
    originY = 0;
    window.addEventListener('scroll', throttle(zoomImage, 250), {passive: true});
    function zoomImage() {
        originY = $(window).scrollTop();
        if (el.isInViewport()) {
            if (!inViewport) {
                inViewport = true; 
            }
        } else {
            if (inViewport) {
                inViewport = false;
            }
        }   
        if (inViewport) {
            if (!isZooming) {
                window.requestAnimationFrame(function () {
                    el.addClass('is-zooming');
                });
                isZooming = true;
            }
        } else {
            if (isZooming) {
                window.requestAnimationFrame(function () {
                    el.removeClass('is-zooming');
                });
                isZooming = false;
            }
        }
    };
    $.fn.isInViewport = function() {
        var elementTop = $(this).offset().top;
        var elementBottom = elementTop + $(this).outerHeight();
        var viewportTop = $(window).scrollTop();
        var viewportBottom = viewportTop + $(window).height();
        return elementBottom > viewportTop && elementTop < viewportBottom;
    };
});

Any help would be greatly appreciated! Thanks a lot!

Attach listeners to containers of the things of interest and the events will "bubble up" to them. (The event-call will tell you which object was the target.)

I found the solution. For anyone who is interested, I solved it like this:

window.addEventListener('scroll', throttle(check_if_in_view, 220), {
    capture: true,
    passive: true
});
var $animation_elements = $('.zoom-images');
var $window = $(window);
function check_if_in_view() {
    var window_height = $window.height();
    var window_top_position = $window.scrollTop();
    var window_bottom_position = (window_top_position + window_height);
    $.each($animation_elements, function() {
        var $element = $(this);
        var $zoom = $(this).children('img.zoom');
        var element_height = $element.outerHeight();
        var element_top_position = $element.offset().top;
        var element_bottom_position = (element_top_position + element_height);
        if ((element_bottom_position >= window_top_position) &&
            (element_top_position <= window_bottom_position)) {
            requestAnimationFrame( function() {
                $zoom.addClass('is-zooming');
            });
        } else {
            requestAnimationFrame( function() {
                $zoom.removeClass('is-zooming');
            });
        }
    });
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM