【问题标题】:Jquery scroll event causing performance issuesJquery 滚动事件导致性能问题
【发布时间】:2013-01-17 11:11:56
【问题描述】:

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

【问题讨论】:

  • 您可以尝试缓存变量以启动。这些变量将被反复调用数百次
  • 了解滚动事件每秒触发多次很重要
  • 是的,卷轴就像疯了一样。您可以考虑使用某种去抖动或节流。

标签: javascript jquery performance scroll


【解决方案1】:

首先,在 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);
    }
});

【讨论】:

    【解决方案2】:

    滚动条的每次移动都会调用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 操作限制在必要的最少数量。

    【讨论】:

    • 谢谢马克,这很有帮助。我对一些语法不熟悉,所以我期待破译一切以扩展我对 JS 的一般知识。再次感谢!
    • 当然可以。我做了一个jsFiddle,你可以用它来炫耀一下。 thresholdCrossed 就像一个标志,只会在您更改状态时触发 if 语句中的代码。祝你好运!
    • 太棒了。这对我来说可能更容易使用,因为我计划添加淡入淡出效果,这样它就不会感觉“跳跃”
    • 恕我直言,这是正确的答案。 Beetroot-Beetroot 建议的节流/去抖动和缓存绝对是有价值的,但首先程序逻辑应该是合理的,这消除了节流的使用。使用建议的 code-sn-p 脚本仅在超过阈值时执行。
    【解决方案3】:

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

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


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

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

    【讨论】:

    • 我明白你在说什么 Kolink。从那以后就完美了。但是,我不能简单地根据滚动位置切换显示,因为我实际上需要滚动位置来指示 .controls 出现的位置。这就是为什么我必须设置克隆以便我可以附加它并根据滚动位置删除它。希望这是有道理的。
    • 我建议的解决方案也使用克隆。只有一个,它是在加载页面的开头创建的。切换元素的显示比克隆要快得多,而且您可以做得更好。等一下,我会用一些代码编辑我的答案。
    • 这是很棒的 Kolink,谢谢!我也将查看 Marc Baumbach 的回应并比较两者。我不熟悉他和你们都使用的一些技术,所以至少这是一次很棒的学习经历。我在上面的例子中可能遇到的唯一问题是添加额外效果的能力。我试图先进行基础设置,然后计划在功能中添加一个不错的淡入淡出。再次感谢!
    • 我在想,你为什么使用 getElementById 和 $('#content')?
    【解决方案4】:

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

              var content = $('#content');
    
              content.scroll(function(){
    
    
              });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-04
      • 2015-02-19
      • 2011-06-24
      相关资源
      最近更新 更多