Jquery页面布局更改优化

时间:2014-05-15 10:57:09

标签: javascript 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);
    });    
});

但是,只要您开始在框中添加任何内容,代码本身就会变得非常迟缓。根据我收到的帮助,我通过动画和查询滚动处理程序中的页面布局属性反复更改页面布局属性,从而触发大量强制布局。

User Tibos said

  

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

有人能告诉我如何实现这种优化吗?

2 个答案:

答案 0 :(得分:3)

Demo page和另一个概念演示: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,从不在任何其他情况下更改。

答案 1 :(得分:1)

您不应该在每个scroll事件中执行此操作。你可以限制事件,只运行每20ms的回调。用户不应该注意到。您可以使用underscore执行此操作,也可以编写自己的解决方案。

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