永久慢慢向下滚动页面,不会占用大量CPU或延迟滚动

时间:2017-07-23 22:37:50

标签: javascript jquery html scroll smooth-scrolling

我想让页面慢慢平滑地向下滚动。那么,速度实际上应该是可调的。用户还应该能够在脚本向下滚动时手动向上滚动。首先我尝试了这个:

var autoScrollDelay = 1
var autoScrollSpeed = 1
var autoScrollTimer
function setAutoScroll(newValue) {
    autoScrollSpeed = newValue ? newValue : autoScrollSpeed
    if (autoScrollTimer) {
        clearInterval(autoScrollTimer)
    }
    if (autoScrollDelay) {
        autoScrollTimer = setInterval(function(){
            window.scrollBy(0,autoScrollSpeed)
      },autoScrollDelay)
    }
}
setAutoScroll(1) // higher number =  faster scrolling

但它导致了非常繁重的CPU负载,而最慢的速度太快了。除此之外,在代码运行时手动向上滚动也无法正常工作。

然后我尝试了:

var autoScrollDelay = 1
var autoScrollSpeed = 1
var autoScrollTimer
function setAutoScroll(newValue) {
    autoScrollDelay = newValue ? newValue : autoScrollDelay //using autoScrollDelay instead of autoScrollSpeed
    if (autoScrollTimer) {
        clearInterval(autoScrollTimer)
    }
    if (autoScrollDelay) {
        autoScrollTimer = setInterval(function(){
            window.scrollBy(0,autoScrollSpeed)
      },autoScrollDelay)
    }
}
setAutoScroll(200) // higher number scrolls slower

但是当设置太慢时(例如200)滚动不顺畅。

然后我尝试了:

$("html, body").animate({
    scrollTop: $('html, body').get(0).scrollHeight, 
}, 40000, "linear");

但是,CPU负载再次过高,手动向上或向下滚动是不可能的。

有更好的方法吗?

2 个答案:

答案 0 :(得分:11)

这是一种可能的实现方式。刷新率是固定的,对应于下面代码中的fps。为了确保速度恒定,我考虑计算新滚动位置后自上一次滚动以来经过的时间。允许手动滚动(使用滚动条,鼠标滚轮或移动设备上的触摸),并通过处理scrollwheeltouchmove事件将其考虑在内。您可以在this codepen中看到代码正常工作。

var fps = 100;
var speedFactor = 0.001;
var minDelta = 0.5;
var autoScrollSpeed = 10;
var autoScrollTimer, restartTimer;
var isScrolling = false;
var prevPos = 0, currentPos = 0;
var currentTime, prevTime, timeDiff;

window.addEventListener("scroll", function (e) {
    // window.pageYOffset is the fallback value for IE
    currentPos = window.scrollY || window.pageYOffset;
});

window.addEventListener("wheel", handleManualScroll);
window.addEventListener("touchmove", handleManualScroll);

function handleManualScroll() {
    // window.pageYOffset is the fallback value for IE
    currentPos = window.scrollY || window.pageYOffset;
    clearInterval(autoScrollTimer);
    if (restartTimer) {
        clearTimeout(restartTimer);
    }
    restartTimer = setTimeout(() => {
        prevTime = null;
        setAutoScroll();
    }, 50);
}

function setAutoScroll(newValue) {
    if (newValue) {
        autoScrollSpeed = speedFactor * newValue;
    }
    if (autoScrollTimer) {
        clearInterval(autoScrollTimer);
    }
    autoScrollTimer = setInterval(function(){
        currentTime = Date.now();
        if (prevTime) {
            if (!isScrolling) {
                timeDiff = currentTime - prevTime;
                currentPos += autoScrollSpeed * timeDiff;
                if (Math.abs(currentPos - prevPos) >= minDelta) {
                    isScrolling = true;
                    window.scrollTo(0, currentPos);
                    isScrolling = false;
                    prevPos = currentPos;
                    prevTime = currentTime;
                }
            }
        } else {
            prevTime = currentTime;
        }
    }, 1000 / fps);
}

setAutoScroll(20);

答案 1 :(得分:5)

来自this article的函数使用vanilla JS以各种速度实现平滑滚动。这是一个演示:



document.getElementById("scrollBottomButton").onclick = function() {
  var duration = document.getElementById("bottomScrollDuration").value * 1000;
  scrollIt(document.querySelector("#bottom-row"), duration, "easeOutQuad");
};

document.getElementById("scrollTopButton").onclick = function() {
  var duration = document.getElementById("topScrollDuration").value * 1000;
  scrollIt(document.getElementById("top-row"), duration, "easeOutQuad");
};

// thanks to https://pawelgrzybek.com/page-scroll-in-vanilla-javascript/
function scrollIt(destination, duration = 200, easing = "linear", callback) {
  const easings = {
    linear(t) {
      return t;
    },
    easeOutQuad(t) {
      return t * (2 - t);
    }
  };

  const start = window.pageYOffset;
  const startTime = "now" in window.performance
  ? performance.now()
  : new Date().getTime();

  const documentHeight = Math.max(
    document.body.scrollHeight,
    document.body.offsetHeight,
    document.documentElement.clientHeight,
    document.documentElement.scrollHeight,
    document.documentElement.offsetHeight
  );
  const windowHeight =
        window.innerHeight ||
        document.documentElement.clientHeight ||
        document.getElementsByTagName("body")[0].clientHeight;
  const destinationOffset = typeof destination === "number"
  ? destination
  : destination.offsetTop;
  const destinationOffsetToScroll = Math.round(
    documentHeight - destinationOffset < windowHeight
    ? documentHeight - windowHeight
    : destinationOffset
  );

  if ("requestAnimationFrame" in window === false) {
    window.scroll(0, destinationOffsetToScroll);
    if (callback) {
      callback();
    }
    return;
  }

  function scroll() {
    const now = "now" in window.performance
    ? performance.now()
    : new Date().getTime();
    const time = Math.min(1, (now - startTime) / duration);
    const timeFunction = easings[easing](time);
    window.scroll(
      0,
      Math.ceil(timeFunction * (destinationOffsetToScroll - start) + start)
    );

    if (window.pageYOffset === destinationOffsetToScroll) {
      if (callback) {
        callback();
      }
      return;
    }

    requestAnimationFrame(scroll);
  }

  scroll();
}


// scroll testing    
var middleHtml = [];

const schiller = "Nur Beharrung führt zum Ziel, Nur die Fülle führt zur Klarheit, Und im Abgrund wohnt die Wahrheit.".split(' ')

for(var i=0; i<schiller.length;i+=1){
  middleHtml.push("<div class=' container row' id='scrolling'><h1 style='margin: 30rem 10rem 30rem 0;font-size: 3.5em;font-family: Helvetica, sans-serif;color: #fff;'>"+schiller[i]+"</h1></div>");
}


document.getElementById('middle').innerHTML = middleHtml.join('');
&#13;
.container-fluid {
background: #e52d27;
background: -webkit-linear-gradient(to top, #b31217, #e52d27);
background: linear-gradient(to top, #b31217, #e52d27);
}

.container-fluid input, .container-fluid .btn {
  border-radius: 0;
}

.btn {
  background: rgba(210,200,200,0.95);
}
&#13;
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"/>

<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"/>

<div class='container-fluid'>
  <div class='row' id='top-row'>
    <div class='col-sm-8'>
      <input class='form-control' id='bottomScrollDuration' placeholder='Enter duration in seconds (4, 25, 40, etc...)' />
    </div>
    <div class='col-sm-4'>
      <button class='btn' id='scrollBottomButton'>Scroll to bottom</button>
    </div>    
  </div>
  <div id='middle'>    
  </div>

  <div class='row' id='bottom-row'>
    <div class='col-sm-8'>
      <input class='form-control' id='topScrollDuration' placeholder='Enter duration in seconds (4, 25, 40, etc...)' />
    </div>
    <div class='col-sm-4'>
      <button class='btn' id='scrollTopButton'>Scroll to top</button>
    </div>
  </div>
</div>
&#13;
&#13;
&#13;

参见 CodePen Demo

<强>更新

如果您只是想调整速度并保持不变的滚动行为,可以试试这个:

function pageScroll(speed) {
    window.scrollBy(0,1);
    scrolldelay = setTimeout(pageScroll,speed);
}

然后以您选择的速度调用该函数,即:

pageScroll(1);

我在Chrome中运行它,并没有对我的CPU使用率征税。当它在Firefox中运行时,CPU确实会出现更多的增长。