Jquery滚动事件导致性能问题

时间:2013-02-02 03:06:36

标签: javascript jquery performance scroll

我正在尝试使用浏览器滚动事件根据用户滚动的数量放置一个html块。该代码有效,但它导致了巨大的性能问题,这基本上迫使我的浏览器冻结。

对于为什么以及我可以采取哪些措施来解决这个问题,我们将非常感激。

<script type="text/javascript">

$('#content').scroll(function () {
    var scroll = $('#content').scrollTop();
    var $controls = $(".controls").clone();
    if (scroll > 200) {
        $(".controls").remove();
        $('#header').append($controls);
    }
    else {
        $(".controls").remove();
        $('.banner').append($controls);
    }
});

</script>

4 个答案:

答案 0 :(得分:13)

首先,发现DOM中的元素是一项昂贵的活动,因此请缓存jQuery对象。

其次,.append()会移动元素,因此.clone()remove()应该是不必要的。

这给出了:

var $$ = {//cache of jQuery objects
    content: $('#content'),
    controls: $(".controls"),
    header: $("#header"),
    banner: $('.banner')
};
$('#content').scroll(function() {
    $controls.appendTo(($$.content.scrollTop() > 200) ? $$.header : $$.banner);
});

现在,您可以努力降低调用处理程序的频率,这可以通过以下方式实现:

var $$ = {//cache of jQuery objects
    content: $('#content'),
    controls: $(".controls"),
    header: $("#header"),
    banner: $('.banner')
};

var scrollHandling = {
    allow: true,
    reallow: function() {
        scrollHandling.allow = true;
    },
    delay: 50 //(milliseconds) adjust to the highest acceptable value
};

$('#content').scroll(function() {
    if(scrollHandling.allow) {
        $controls.appendTo(($$.content.scrollTop() > 200) ? $$.header : $$.banner);
        scrollHandling.allow = false;
        setTimeout(scrollHandling.reallow, scrollHandling.delay);
    }
});

答案 1 :(得分:3)

为滚动条的每次移动调用scroll函数。这可能有很多次,所以你需要注意你运行的代码数量,以及你正在对DOM进行多少操作。

在这种情况下,当您进行滚动时,您将重复许多相同的操作(cloneappendremove),但您似乎只想要当你在200 scroll值之间来回穿过时,在两个状态之间切换。您可以通过以下方式解决大多数性能问题:

<script type="text/javascript">

var thresholdCrossed = false;

$('#content').scroll(function () {
    var scroll = $('#content').scrollTop();
    var threshold = 200;
    if (scroll > threshold && !thresholdCrossed) {
        var controls = $(".controls").clone();
        $(".controls").remove();
        $('#header').append(controls);
    } else if (scroll <= threshold && thresholdCrossed) {
        var controls = $(".controls").clone();
        $(".controls").remove();
        $('.banner').append(controls);
    }
    thresholdCrossed = scroll > threshold;
});

</script>

您可以执行其他一些答案所描述的其他工作,以帮助减少浪费的资源,但这应该让您大致了解如何在滚动时如何有希望地帮助主要的性能问题,即不断修改DOM。我可能会建议将这一点与@Kolink提供的答案结合起来,以便您真正将DOM操作限制在最少的必要量。

答案 2 :(得分:2)

即使不需要,您也会在每次滚动时刻录所有.controls个元素。

我建议克隆ready上的控件并将其设置为display:none。然后,只需根据滚动位置切换显示。


在重新阅读您的问题时,您似乎只是将控件元素从header移动到banner?在这种情况下,您甚至不需要克隆。但是我强烈建议将id="controls"添加到controls元素,id="banner" - 如果只有一个,则使用ID而不是类。

document.getElementById('content').onscroll = function() {
    document.getElementById(this.scrollTop > 200 ? "banner" : "header")
       .appendChild(document.getElementById('controls'));
};

答案 3 :(得分:0)

每次滚动条移动时,jQuery必须进入DOM以获取您引用的变量。要开始缓存变量,所以jQuery不需要做两倍的工作。

          var content = $('#content');

          content.scroll(function(){


          });