Jquery页面布局改变优化



我有这段代码,它完全按照我想要的方式工作。菜单栏位于顶部,并识别它所在的部分。您可以单击黄色菜单中的链接在各节之间移动。

演示:http://jsfiddle.net/spadez/2atkZ/9/和http://jsfiddle.net/spadez/2atkZ/9/embedded/result/

$(function () {
    var $select = $('#select');
    var $window = $(window);
    var isFixed = false;
    var init = $select.length ? $select.offset().top : 0;
    $window.scroll(function () {
        var currentScrollTop = $window.scrollTop();
        if (currentScrollTop > init && isFixed === false) {
            isFixed = true;
            $select.css({
                top: 0,
                position: 'fixed'
            });
            $('body').css('padding-top', $select.height());
        } else if (currentScrollTop <= init) {
            isFixed = false;
            $select.css('position', 'relative');
            $('#select span').removeClass('active');
            $('body').css('padding-top', 0);
        } 

        //active state in menu
        $('.section').each(function(){
            var eleDistance = $(this).offset().top;
            if (currentScrollTop >= eleDistance-$select.outerHeight()) {
                var makeActive = $(this).attr('id');
                $('#select span').removeClass('active');
                $('#select span.' + makeActive).addClass('active');
            }
        });
    });
    $(".nav").click(function (e) {
        var divId = $(this).data('sec');
        $('body').animate({
            scrollTop: $(divId).offset().top - $select.height()
        }, 500);
    });    
});

然而,一旦您开始将任何内容放入框中,代码本身就会变得相当滞后。根据我收到的帮助,这是我通过动画反复改变页面布局属性,并在滚动处理程序中查询页面布局属性,从而触发大量的强制布局。

用户Tibos说:

您可以通过禁用滚动处理程序来获得很大的改进点击动画,而不是触发没有检查的效果制作(在被点击的元素上设置活动类)

谁能告诉我如何才能实现这个优化?

演示页面和另一个概念演示:http://codepen.io/vsync/pen/Kgcoa

这里的关键是将你的select放置在另一个元素中,所以当它被固定到屏幕上时,它不会因为突然缺乏高度而影响其他元素。我还添加了一些CSS。使用jQuery 1.11或更高版本是很重要的,因为它们修正了导致同一个类被一次又一次添加的但是,而不管一个元素是否已经有了它。对性能不利。此外,我在section元素上使用了for循环而不是jquery each循环,因为for循环由于缺少each函数回调而更快。另外,很重要的一点是要确保每个可以被缓存的元素都被缓存了,这样我们就不会在DOM中没完没了地寻找它了。

为了显示我们在哪个部分,我循环所有的部分,从最后一个开始,这是很重要的,并检查每个顶部是否已经通过窗口的顶部使用getBoundingClientRect方法来知道这样的事情。这有助于知道我们在哪里。

var pos,
    $el = $('#select'),
    navItems = $el.find('.nav'),
    menuHeight = $el[0].clientHeight,
    scrollY,
    sections = $('.section').toArray(),  // cache sections elements
    pointOfAttachment = $('.jumbo')[0].clientHeight - menuHeight;
// Bind events
$(window).on('scroll.nav', updateNav)
         .on('resize.nav', updateNav);

function updateNav(){
    scrollY = window.pageYOffset || document.documentElement.scrollTop;
    for( var i = sections.length; i--; ){
        if( sections[i].getBoundingClientRect().top < 0 ){
            navItems.filter('.' + sections[i].id).addClass('active').siblings().removeClass('active');
            break;
        }
        navItems.removeClass('active');
    }
    if( scrollY > pointOfAttachment )
        $el.addClass('fixed');
    else
        $el.removeClass('fixed');
}

为什么这是最优的?

获得良好性能的关键是尽可能少地实现您的目标,这里的"最小"意味着尽可能少地访问DOM,并且更改它的次数甚至比访问它的次数还要少。这是高度优化的代码,只在需要更改时更改DOM,而不会在任何其他情况下更改。

您不需要在每个scroll事件上都这样做。您可以限制事件,每隔20毫秒才运行一次回调。用户不应该注意到。您可以使用下划线来完成此操作,或者编写您自己的解决方案。

另一个可以缓解延迟的方法是尽可能多地移出滚动事件回调。您不需要一直查询$('body'),例如,将其保存为变量

最新更新