javascript - jQuery $(window).scroll 事件处理程序关闭但仍在触发?

标签 javascript jquery underscore.js squarespace

我在使用我编写的 jQuery 插件时遇到了一些奇怪的行为。基本上,当滚动侧边栏所属的博客文章时,该插件会使侧边栏元素粘在浏览器窗口的顶部。仅当窗口达到一定大小(768px)或以上时才会发生这种情况(插件通过检查侧边栏的 float 样式来检测到这一点)。

一切都按预期进行...直到您将浏览器的大小从大(侧边栏粘性)调整为小(侧边栏不应该粘性)。据推测,我的 onResize 函数会删除滚动事件处理程序,并且仅在 startQuery 为 true 时才将其添加回来(因此,如果侧边栏浮点值不是无)。我已经通过控制台进行了两次和三次检查:据我所知,一切都正常工作。我什至将 console.log('scroll') 添加到 onScroll 函数,当应该删除事件处理程序时它不会显示,但我的侧边栏仍然 当我滚动浏览博客文章时变得粘滞。

您可以看到实际问题 here 。要重新创建步骤:

  1. 将浏览器窗口的宽度调整为小于 768 像素并访问该页面。请注意,当您滚动时,每个博客文章中的 .share-bar 元素不会移动。 “scroll”未记录在控制台中。
  2. 将浏览器窗口大小调整为 768 像素或更大。当您滚动浏览每篇博客文章时,会发现 .share-bar 元素会变得粘性,然后当您滚动经过它时会粘在文章的底部。 “scroll”已记录在控制台中。
  3. 将浏览器窗口大小调整为小于 768 像素。当您滚动浏览每篇博客文章时,会发现 .share-bar 元素变得粘滞。 “scroll”未记录在控制台中。

这几乎就像事件处理程序被删除一样,但元素没有更新或其他什么。我确信我错过了一些基本的东西,但我已经研究并尝试了针对 $(window).scroll 事件问题的各种修复,但它们都不起作用。

我对插件的调用:

$('.share-bar').stickySides({ 
    'wrapper': '.post-wrapper', 
    'content': '.entry-content' });

插件代码:

;( function ( $, window, document, undefined ) {

var settings;
var throttled;

$.fn.stickySides = function( options ) {

    settings = $.extend( {}, $.fn.stickySides.defaults, options );

    // Store sidebars
    settings.selector = this.selector;
    settings.startQuery = '$("' + settings.selector + '").css(\'float\') != \'none\'';

    // Create debounced resize function
    var debounced = _.debounce( $.fn.stickySides.onResize, settings.wait );
    $(window).resize( debounced );

    // Create throttled scroll function
    throttled = _.throttle( $.fn.stickySides.onScroll, settings.wait );
    // Only continue if the start query is true
    if ( eval(settings.startQuery) == true ) {
        $(window).on( 'scroll.stickySides', throttled );    
    }

    return this;
};

// Define default settings
$.fn.stickySides.defaults = {
    wrapper: 'body',
    content: '.content',
    wait: 100,
    startQuery: ''
};

$.fn.stickySides.onResize = function ( ) {

    $(window).off( 'scroll.stickySides' );

    // Only continue if the start query is true
    if ( eval(settings.startQuery) == true ) {

        $(window).on( 'scroll.stickySides', throttled );

    } else {

        var sides = $(settings.selector);
        sides.each ( function () {

            var elem = $(this);
            var content = elem.siblings( settings.content );

            if ( elem.css('position') == 'fixed' || elem.css('position') == 'absolute' ) {
                elem.css( 'position', 'static' );
            }

            if ( content.css('margin-left') != '0px' ) {
                content.css( 'margin-left', 0 );
            }

        });

    }

};

$.fn.stickySides.onScroll = function ( ) {

    console.log('scroll');      
    var sides = $(settings.selector);

    // Check each sidebar
    sides.each ( function () {

        var elem = $(this);
        var content = elem.siblings( settings.content );
        var wrapper = elem.closest( settings.wrapper );

        var elemHeight = elem.height();
        var wrapperHeight = wrapper.height();

        // Only continue if the wrapper is taller than the sidebar 
        if ( elemHeight >= wrapperHeight ) {

            return;

        } else {

            var wrapperFracs = wrapper.fracs(function (fracs) {

                // Only continue if the wrapper is in view
                if ( fracs.visible == 0 ) {

                    return;

                } else {

                    // Check if the wrapper extends beyond the top of
                    // the viewport
                    var wrapperSpaceTop = fracs.rects.element.top;

                    // If it does, change sidebar position as appropriate
                    if ( wrapperSpaceTop > 0 ) {

                        var visibleWrapper = fracs.rects.document.height;

                        // If the visible portion of the wrapper is smaller
                        // than the height of the sidebar...
                        if ( visibleWrapper <= elemHeight ) {

                            // ...position the sidebar at the bottom
                            // of the wrapper
                            if ( wrapperSpaceTop != 0 ) {

                                elem.css('position', 'absolute').css( 'top', (wrapperHeight - elemHeight) + content.position().top + 'px' );

                            } 

                        // Otherwise, move sidebar to appropriate position
                        } else {

                            elem.css('position', 'fixed').css('top', 0);

                        }

                        content.css('margin-left', elem.outerWidth());

                    } else {

                        elem.css('position', 'static');
                        content.css('margin-left', 0);

                    }

                }
            });


        }


    });

};

} )( jQuery, window, document );

PS:我会使用现有的插件,但我没有看到一个真正接近我需要的功能的插件;如果您知道其中之一,请随时指出。我还没有在 Mac 之外进行测试。是的,我知道一些页面元素在移动设备上流动得不太好 - 例如:网站标题和导航 - 并且还有一些与此问题无关的其他缺失项目。我正在等待客户的一些反馈,然后才能解决这个问题。

最佳答案

每次都会发生。在我寻求帮助后不久,我就自己解决了。 ;)

问题出在 onScroll 函数内的 fracs 函数中。我没有意识到它调用了自己的调整大小/滚动处理程序,因此当我删除我的滚动处理程序时,那些并没有解除绑定(bind)。我只是重新设计了插件以利用 fracs 库的处理程序,而不是调用我自己的滚动处理程序:

;( function ( $, window, document, undefined ) {

var settings;
var throttled;

$.fn.stickySides = function( options ) {

    settings = $.extend( {}, $.fn.stickySides.defaults, options );

    // Store sidebars
    settings.selector = this.selector;
    settings.startQuery = '$("' + settings.selector + '").css(\'float\') != \'none\'';

    if ( eval( settings.startQuery ) == true ) {

        $.fn.stickySides.doFracs();

    }

    // Create debounced resize function
    var debounced = _.debounce( $.fn.stickySides.onResize, settings.wait );
    $(window).resize( debounced );

    return this;
};

// Define default settings
$.fn.stickySides.defaults = {
    wrapper: 'body',
    content: '.content',
    wait: 100,
    startQuery: ''
};

$.fn.stickySides.doFracs = function ( ) {

    var sides = $(settings.selector);

    // Check each sidebar
    sides.each ( function () {

        var elem = $(this);
        var content = elem.siblings( settings.content );
        var wrapper = elem.closest( settings.wrapper );

        var elemHeight = elem.height();
        var wrapperHeight = wrapper.height();

        // Only continue if the wrapper is taller than the sidebar 
        if ( elemHeight >= wrapperHeight ) {

            return;

        } else {

            var wrapperFracs = wrapper.fracs( $.fn.stickySides.fracsCallback );

        }

    });

}

$.fn.stickySides.unbindFracs = function ( ) {

    var sides = $(settings.selector);

    // Check each sidebar
    sides.each ( function () {

        var elem = $(this);
        var content = elem.siblings( settings.content );
        var wrapper = elem.closest( settings.wrapper );


        if ( elem.css('position') == 'fixed' || elem.css('position') == 'absolute' ) {
            elem.css( 'position', 'static' );
        }

        if ( content.css('margin-left') != '0px' ) {
            content.css( 'margin-left', 0 );
        }

        wrapper.fracs('unbind');

    });

}

$.fn.stickySides.fracsCallback = function ( fracs ) {

    // Only continue if the wrapper is in view
    if ( fracs.visible == 0 ) {

        return;

    } else {

        var wrapper = $(this);
        var elem = wrapper.find(settings.selector);
        var content = elem.siblings( settings.content );

        var elemHeight = elem.height();
        var wrapperHeight = wrapper.height();

        // Check if the wrapper extends beyond the top of
        // the viewport
        var wrapperSpaceTop = fracs.rects.element.top;

        // If it does, change sidebar position as appropriate
        if ( wrapperSpaceTop > 0 ) {

            var visibleWrapper = fracs.rects.document.height;

            // If the visible portion of the wrapper is smaller
            // than the height of the sidebar...
            if ( visibleWrapper <= elemHeight ) {

                // ...position the sidebar at the bottom
                // of the wrapper
                if ( wrapperSpaceTop != 0 ) {

                    elem.css('position', 'absolute').css( 'top', (wrapperHeight - elemHeight) + content.position().top + 'px' );

                } 

            // Otherwise, move sidebar to appropriate position
            } else {

                elem.css('position', 'fixed').css('top', 0);

            }

            content.css('margin-left', elem.outerWidth());

        } else {

            elem.css('position', 'static');
            content.css('margin-left', 0);

        }

    }

}

$.fn.stickySides.onResize = function ( ) {

    // Only continue if the start query is true
    if ( eval(settings.startQuery) == true ) {

        $.fn.stickySides.doFracs();

    } else {

        $.fn.stickySides.unbindFracs();

    }

};


} )( jQuery, window, document );

瞧!问题解决了。

关于javascript - jQuery $(window).scroll 事件处理程序关闭但仍在触发?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36808960/

相关文章:

javascript打印特定的div

javascript - 如何从 angularjs 中的 Controller CandidateCtrl.js 访问 Data.js 的功能?

javascript - 下划线模板的自定义解析

javascript - 使用下划线展开功能

javascript - 检索导航属性动态 WebAPI

javascript - JQuery 函数从多个 .js 脚本列表中加载 DIV

javascript - 插入时动态创建的 DOM 节点的处理程序

javascript - 如何对对象使用 Underscore.js 过滤器?

javascript - polymer-textarea 在我看来应该出现时没有出现

javascript - 如何每 5 秒运行一个函数,每次都有不同的值?