使用缓动功能滚动

时间:2015-11-22 19:22:54

标签: javascript dom easing

我编写了一个函数,在调用时,会以平滑的方式向下滚动页面。

问题是滚动的数量不准确。它可以关闭一个像素左右,具体取决于滚动的距离和滚动的持续时间。

有没有更好的方法来做到这一点,滚动可以移动所需像素的确切数量?

const EASING = BezierEasing(0, .1, .1, 1); // Example values.
const DURATION = 1000; // ms.

document.addEventListener('DOMContentLoaded', 
  () =>  {
    document.querySelector('#foo')
      .addEventListener('click', onClick, false);
});

function onClick(e) {
  scroll(400); // px.
  e.preventDefault();
  return false;
}

function scroll(distance) {
  var start, travelled, html;

  start = performance.now();
  travelled = 0;
  html = document.querySelector('html');

  (function move(now) {
    var fractionDone, dy, toMove;

    fractionDone = (now-start) / DURATION;

    if((1 - fractionDone) <= 0) {
      return; // Done!
    }

    if(window.scrollY + window.innerHeight 
      === html.offsetHeight) {
      return; // At bottom of page.
    }

    dy = ((EASING.get(fractionDone)) * distance);
    toMove = Math.floor((dy - travelled)); // `scrollBy` only accepts integers.

    if(toMove > 0) {
      window.scrollBy(0, toMove);
      travelled += toMove;
    }

    requestAnimationFrame(move);
  }(start));
}
<!DOCTYPE html>
<html>
  <head>
    <script src="https://rawgit.com/gre/bezier-easing/master/build.js"></script>
  </head>
  <body>
    <a href id="foo">Click Me!</a>
    <script>
      /* print some numbers to
           the DOM to help visualize 
           the scrolling */
      var body = document.querySelector('body');
      for(var x = 0; x < 50; x++) {  
        var div = document.createElement("div"); 
        var text = document.createTextNode(x);
        div.appendChild(text);
        body.appendChild(div);
      }
    </script>
  </body> 
</html>

2 个答案:

答案 0 :(得分:1)

你可以做这样的事情来解释最后一次迭代吗?

基本上如果toMove向下舍入到0,但距离还没有到达,强迫它再滚动一次?

if(toMove > 0 || (toMove == 0 && travelled != distance) {
  window.scrollBy(0, (toMove ? toMove : 1));
  travelled += toMove;
}

答案 1 :(得分:0)

我决定修改完成逻辑以移动任何剩余距离:

// ...
if((1 - fractionDone) <= 0) {
  window.scrollBy(0, (distance - travelled)); // Scroll any remaining distance.
  return; // Done!
}
// ...

我认为,这解决了这个问题。