固定具有去抖动滚动事件的元素以提高性能

时间:2019-08-24 23:47:11

标签: javascript jquery performance scroll debounce

根据滚动位置平滑固定元素的正确方法是什么? 我尝试取消滚动监听器的性能,但固定不准确。即使将反跳设置为10ms,它也不平滑,并且元素也不能干净地捕捉到其初始位置。

var scrolling = false;
var stickPosY = 100;
var heights = [];

$(".element").each( function(index) {
  heights[index] = $(".element[data-trigger=" + index + "]").offset().top;
});

function pin() {
  if ( !$("#aside").hasClass("fixed") ) {

    var stickyLeft = $("#aside").offset().left;
    var stickyWidth = $("#aside").outerWidth();
    var stickyTop = $("#aside").offset().top - stickPosY;

    $("#aside").addClass("fixed"); 
    $("#aside").css({"left": stickyLeft, "top": stickyTop, "width": stickyWidth});
  }
}

function unpin() {
  $("#aside").css({"left": "", "top": "", "width": ""});
  $("#aside").removeClass("fixed")
}

$( window ).scroll( function() {
  scrolling = true;
});

setInterval( function() {
  if ( scrolling ) {
    scrolling = false;

    var y = window.scrollY;
    console.log(y);

    // PIN SIDEBAR
    y > stickPosY ? pin() : unpin();

    //TRIGGERS
    for (var i=0; i < heights.length; i++) {  
      if (y >= heights[i]) {
        $('.element[data-trigger="' + i + '"]').addClass("blue");
      }
      else {
        $('.element[data-trigger="' + i + '"]').removeClass("blue");
      }
    }
  }
}, 250 );

这是我的Pen

我尝试将scrollMagic用于带有引脚和其他触发器的场景中的项目,但滚动不是很流畅。因此,我正在尝试使用精简版和侦听器反弹来重建它。这种方法可行吗?还是我应该尝试优化scrollMagic场景?

2 个答案:

答案 0 :(得分:0)

您可以尝试fixed or sticky CSS positioning

#element {
  position: fixed;
  top: 80px;
  left: 10px;
}

位置:固定后,无论滚动位置如何,该元素始终始终保持顶部80像素和左侧10像素。

  #element{
    position: sticky;
    top: 0;
    right: 0;
    left: 0;
  }

这是我的一个项目。元素是导航栏。它位于标题栏下方,因此当您位于页面顶部时,您会看到标题,然后是其下方的导航栏;向下滚动时,标题移出屏幕,但导航栏会停留在顶部,并且始终可见

答案 1 :(得分:0)

正如James指出的那样,您只能使用position: sticky作为一个选项,但这在旧版浏览器中不起作用,并且它的使用仅限于新版浏览器中的简单情况,因此我将继续使用JS假设您想走那条路线的解决方案。

您的JS中发生了很多事情,我认为您可能使事情复杂化了,所以我将为您提供一些基础知识。

  1. 当您基于滚动切换内容时,可以切换内联样式或类,但不能同时切换两者。我建议切换一个类,因为它允许您使用一个可以在多种屏幕尺寸上使用的功能(即您可以使用媒体查询根据屏幕尺寸来更改切换后的类的行为)。还将所有样式保留在一个位置,而不是在JS和样式表之间分割样式。

  2. 尽量保持滚动状态,同时尽量减少滚动。例如,对滚动功能之外的变量中的元素的引用进行高速缓存,以便您不必在每次滚动像素时都不断查找它们。避免滚动功能内部循环。

  3. 通常不建议使用setInterval来提高滚动功能的性能。不管您是否滚动,所有需要做的就是每隔X时间运行一次函数。您真正想做的是直接限制滚动功能的速率。这样,如果您真正快速地滚动很长一段距离,您的函数将仅被调用,否则它将被称为总次数的一部分,但是如果您缓慢滚动一小段距离,它仍将被称为保持事物最少的次数看起来很平滑,如果根本不滚动,那么根本就不会调用函数。另外,在这种情况下,您可能想节制功能,而不是对其进行反跳操作。

  4. 考虑使用Underscore.js或Lodash.js中的节流功能,而不要发明自己的功能,因为这些功能高效能并且可以在各种浏览器上使用。

这是一个简单的示例,在滚动时将元素粘贴到屏幕顶部,并受Lodash限制。我正在使用25ms的油门,这是我为保持外观平滑而建议的最大数量,当您滚动阈值时不会真正注意到元素粘连/不粘连的延迟。您可能会低至10毫秒。

$(function() {
  $(window).on('scroll', _.throttle(toggleClass, 25));

  const myThing = $('#my-thing');
  const threshold = $('#dummy-1').height();

  function toggleClass() {
    const y = window.scrollY;
    if (y > threshold) {
      myThing.addClass('stuck')
    } else {
      myThing.removeClass('stuck');
    }
  }
});
#dummy-1 {
  height: 150px;
  background-color: steelblue;
}
#dummy-2 {
  height: 150px;
  background-color: gold;
}
#my-thing {
  width: 300px;
  height: 75px;
  background-color: firebrick;
  position: absolute;
  top: 150px;
  left: 0;
}
#my-thing.stuck {
  position: fixed;
  top: 0;
}
body {
  margin: 0;
  height: 2000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.0.0/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="dummy-1"></div>
<div id="dummy-2"></div>
<div id="my-thing"></div>