永久缓慢地向下滚动页面,而不会占用大量 CPU 或延迟滚动
Posted
技术标签:
【中文标题】永久缓慢地向下滚动页面,而不会占用大量 CPU 或延迟滚动【英文标题】:Slowly scroll down a page permanently without heavy CPU usage or laggy scrolling 【发布时间】:2017-12-29 10:39:03 【问题描述】:我想让页面缓慢而流畅地向下滚动。嗯,速度实际上应该是可调的。用户还应该能够在脚本向下滚动时手动向上滚动。首先我尝试了这个:
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 负载再次过高,无法通过这种方式手动向上或向下滚动。
有没有更好的方法来做到这一点?
【问题讨论】:
CSS translateY 可能是您的最佳选择。 你能链接到你的页面吗?页面重量是多少?页面滚动时您是否有很多沉重的图像或动画或发生的任何事情? 我在哪个页面上运行代码并不重要。你可以在 *** 上尝试一下。我的 Firefox 显示 10-12% 的 cpu 负载,这可能与单线程脚本在 8 线程 cpu 上的负载一样多。 我的答案是:不要乱滚动..没有插件/好方法可以创建自定义滚动行为 【参考方案1】:这是一种可能的实现方式。刷新率是固定的,对应下面代码中的fps
。为了确保速度恒定,我在计算新的滚动位置时考虑了自上次滚动以来经过的时间。允许手动滚动(使用滚动条、鼠标滚轮或触摸移动设备)并通过处理scroll
、wheel
和touchmove
事件来考虑。您可以在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);
【讨论】:
有什么方法可以在运行时允许手动滚动? @Forivin - 使用当前代码,我可以在自动滚动进行时手动滚动(在 Chrome、FF 和 IE 上使用 the codepen 进行了测试)。你不能? 并非如此。感觉非常反应迟钝。即使我尝试尽可能快地手动向上或向下滚动,我也几乎看不到任何反应。就像手动滚动距离设置为 1px 并且仅每 2 秒工作一次。在 chromium 和 firefox 中测试(启用平滑滚动)。如果我在 Firefox 中禁用平滑滚动,它实际上工作正常。但我需要一种适用于两种模式的解决方案。 我正在使用滚动条测试“手动滚动”,没有任何问题。也许您正在使用鼠标滚轮。你可以试试this codepen,里面包含了一些鼠标滚轮事件的代码。 你可以试试this codepen。针对wheel
和touchmove
事件处理手动滚动。然而,我在 iPad 上的测试并不成功(自动滚动本身不起作用)。在 ios 上滚动似乎完全不同...【参考方案2】:
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('');
.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);
<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>
见CodePen Demo
更新
如果您只是想调整速度并保持恒定的滚动行为,您可以试试这个:
function pageScroll(speed)
window.scrollBy(0,1);
scrolldelay = setTimeout(pageScroll,speed);
然后以您选择的速度调用该函数,即:
pageScroll(1);
我在 Chrome 中运行它,它并没有占用我的 CPU 资源。在 Firefox 中运行时,CPU 确实会出现更多峰值。
【讨论】:
这段代码在 CPU 上似乎更轻,速度取决于页面的高度,因为您设置了滚动持续时间而不是滚动速度。哦,到达底部时滚动不应该停止。 您可以在此功能中选择要滚动到的位置,但我想这不是您想要的。如果页面底部没有停止滚动,滚动是如何停止的?用户是否停止滚动?超时了吗? @Forivin 我已经用一个较小的函数更新了我的答案,该函数不会使 Chrome 中的 CPU 使用率飙升。但是,当它在 Firefox 中运行时,CPU 使用率确实会飙升。 该函数的问题与我的第一个代码 sn-p 的问题完全相同。即使以 1 的速度滚动也太快了,它会导致相同的 CPU 负载(至少在最新的 Firefox 上)并且手动向上滚动无法正常工作。 如果用户想在某个点停止滚动,您还应该添加 .stop 来中断滚动。看看这个作为参考:***.com/a/18445654/4465062以上是关于永久缓慢地向下滚动页面,而不会占用大量 CPU 或延迟滚动的主要内容,如果未能解决你的问题,请参考以下文章