web-dev-qa-db-ja.com

CPUの使用率が高くなったり、スクロールが遅くなったりすることなく、ページを永続的にゆっくりと下にスクロールする

ページをゆっくりとスムーズにスクロールさせたい。まあ、速度は実際に調整可能でなければなりません。スクリプトが下にスクロールしている間、ユーザーは手動で上にスクロールできる必要もあります。まず私はこれを試しました:

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の負荷が非常に高く、手動で上下にスクロールすることはできませんでした。

これを行うより良い方法はありますか?

11
Forivin

これが可能な実装の1つです。リフレッシュレートは固定されており、以下のコードのfpsに対応しています。速度が一定であることを確認するために、新しいスクロール位置を計算するときに、前回のスクロールからの経過時間を考慮します。手動スクロールは許可され(スクロールバー、マウスホイール、またはモバイルデバイスのタッチ)、scrollwheel、および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);
13
ConnorsFan

この記事 の関数は、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のスパイクが大きくなります。

5
Dan Kreiger