3

我正在尝试使用浏览器滚动事件根据用户滚动的数量放置一个 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

4 回答 4

14

首先,在 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);
    }
});
于 2013-02-02T03:31:55.477 回答
3

滚动条的每次移动都会调用该scroll函数。这可能是很多次,所以你需要小心你运行了多少代码,当然还有你正在对 DOM 进行多少操作。

在这种情况下,当滚动发生时,您将重复许多相同的操作(cloneappend、 ),但是当您在 200值remove上来回交叉时,您似乎只想在两个状态之间翻转。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 操作限制在必要的最少数量。

于 2013-02-02T03:23:50.120 回答
2

每次滚动时,您都在克隆所有.controls元素,即使在不需要时也是如此。

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


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

document.getElementById('content').onscroll = function() {
    document.getElementById(this.scrollTop > 200 ? "banner" : "header")
       .appendChild(document.getElementById('controls'));
};
于 2013-02-02T03:09:35.027 回答
0

每次滚动条移动时,jQuery 都必须进入 DOM 以获取您引用的变量。开始缓存变量,这样 jQuery 就不必做两次工作了。

          var content = $('#content');

          content.scroll(function(){


          });
于 2013-02-02T03:11:51.110 回答