Javascript 移动safari上的粘性元素问题

Javascript 移动safari上的粘性元素问题,javascript,html,css,Javascript,Html,Css,我有一个元素,我希望在向下滚动时将其粘贴到页面顶部。从功能上讲,所有代码都可以工作,这要感谢其他用户。然而,当在手机上向下滚动时,粘性元素似乎落后了一点。我的意思是,每当父元素滚动时,代码似乎都在调用,它会对粘性元素进行成百上千的调整,从而使其稍微抖动 代码如下: HTML CSS 您需要做的是限制或消除调用以更新元素 还有,为什么要将滚动侦听器附加到包装器滚动处理程序内的窗口?这意味着每次调用滚动监听器时,它都会将另一个滚动监听器附加到窗口 您所需要的只是窗口上的单个处理程序,并允许传播来完成

我有一个元素,我希望在向下滚动时将其粘贴到页面顶部。从功能上讲,所有代码都可以工作,这要感谢其他用户。然而,当在手机上向下滚动时,粘性元素似乎落后了一点。我的意思是,每当父元素滚动时,代码似乎都在调用,它会对粘性元素进行成百上千的调整,从而使其稍微抖动

代码如下:

HTML

CSS

您需要做的是限制或消除调用以更新元素

还有,为什么要将滚动侦听器附加到包装器滚动处理程序内的窗口?这意味着每次调用滚动监听器时,它都会将另一个滚动监听器附加到窗口

您所需要的只是窗口上的单个处理程序,并允许传播来完成其余的工作

// A debounce function wraps a function with a setTimeout,
// and then resets that timeout everytime it is called

function debounce(func, delay){
  var timeout, that = this;

  delay = delay || 300;

  return function() {
    if(timeout) clearTimeout(timeout)
    timeout = setTimeout(function() {
      return func.apply(that, arguments)
    }, delay)
  }
}

// a throttle function ensures that a function isn't
// called more than once every interval

function throttle(fn, interval, shouldDebounce){
  var lastCall = 0, debouncedFn;

  interval = interval || 300

  if(shouldDebounce) debouncedFn = debounce(fn, interval);

  return function(){
    var now = (new Date()).getTime();
    if(now - lastCall < interval)
      return debouncedFn && debouncedFn.apply(this, arguments);

    lastCall = now;
    return fn.apply(this, arguments);
  }
}

// create a function to set scroll listeners
function setScroller() {
  var $anchor = $("#scroller-anchor"),
      $scroller = $('#scroller'),
      onMove = function onMove() {
        var st = $(window).scrollTop(),
            ot = $anchor.offset().top;

        if(st > ot) { 
          $scroller.addClass('fixedElement');
        } else {
          $scroller.removeClass('fixedElement');
        }
      },
      // Throttle the onMove function to make sure it isn't called too often
      throttlededOnMove = throttle(onMove, 300);

  $(window).scroll(throttlededOnMove);
}

// attach scroll listener on document ready
$(setScroller)

在我看来,一个可能的更有效的解决方案是使用position:CSS中的sticky而不是JS。您还需要提供top:0。IE的某些兼容性落后,但它已经是一个可行的解决方案。值得一查


如果您担心旧浏览器,您可能会在JS中添加一个回退功能,这仍然有些滞后

什么是去盎司功能?我在答案中添加了一个示例函数。去抖动意味着如果在最后一次调用超时完成之前再次调用该函数,它将清除超时并等待again@chris更新了我的答案,以限制调用的数量,而不是取消调用,因为某些原因,这并没有像预期的那样应用我的css类。它确实进入了必要的if语句部分,但是css类从未被添加,也没有抛出任何奇怪的错误。请确保$scroller变量包含正确的元素。是否有其他事件正在该元素中添加和删除类?除此之外,jQuery中的一个bug超出了这个问题的范围。这就是我在我的应用程序中所做的,但是粘性支持还没有完全实现,所以适当限制JS回退仍然是一个好主意
    $('#scroller-wrapper').scroll(function() {
      var $anchor = $("#scroller-anchor");
      var $scroller = $('#scroller'); 
      var move = function() {
        var st = $(window).scrollTop();
        var ot = $anchor.offset().top;
        if(st > ot) { 
          $scroller.addClass('fixedElement');
        } else {
          $scroller.removeClass('fixedElement');
        }
    };
    $(window).scroll(move);
    move();
});
.fixedElement {
  position:fixed;
  top:0;
  right:0;
  width:100%;
  z-index:10000;
}
// A debounce function wraps a function with a setTimeout,
// and then resets that timeout everytime it is called

function debounce(func, delay){
  var timeout, that = this;

  delay = delay || 300;

  return function() {
    if(timeout) clearTimeout(timeout)
    timeout = setTimeout(function() {
      return func.apply(that, arguments)
    }, delay)
  }
}

// a throttle function ensures that a function isn't
// called more than once every interval

function throttle(fn, interval, shouldDebounce){
  var lastCall = 0, debouncedFn;

  interval = interval || 300

  if(shouldDebounce) debouncedFn = debounce(fn, interval);

  return function(){
    var now = (new Date()).getTime();
    if(now - lastCall < interval)
      return debouncedFn && debouncedFn.apply(this, arguments);

    lastCall = now;
    return fn.apply(this, arguments);
  }
}

// create a function to set scroll listeners
function setScroller() {
  var $anchor = $("#scroller-anchor"),
      $scroller = $('#scroller'),
      onMove = function onMove() {
        var st = $(window).scrollTop(),
            ot = $anchor.offset().top;

        if(st > ot) { 
          $scroller.addClass('fixedElement');
        } else {
          $scroller.removeClass('fixedElement');
        }
      },
      // Throttle the onMove function to make sure it isn't called too often
      throttlededOnMove = throttle(onMove, 300);

  $(window).scroll(throttlededOnMove);
}

// attach scroll listener on document ready
$(setScroller)