代码之家  ›  专栏  ›  技术社区  ›  Forivin

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

  •  11
  • Forivin  · 技术社区  · 7 年前

    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 回复  |  直到 7 年前
        1
  •  19
  •   ConnorsFan    7 年前

    这里是一个可能的实现。刷新率是固定的,对应于 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);
    
        2
  •  5
  •   Dan Kreiger    7 年前

    函数来自 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的峰值会更大。