平滑滚动跨浏览器

3

我尝试不重复造轮子,使用现有的滚动脚本,但是我发现所有的脚本都使用jQuery(我不想将代码弄乱),而且没有支持按键和滚动div的功能……都不够好。

我使用的操作系统是Windows 7:Opera和Chrome的滚动不够顺畅,所以我写了代码来提供顺畅的滚动体验。然而,在默认已经具备顺滑滚动功能的Explorer 11中,我的脚本会导致过度敏感。我的朋友在Mac OS上运行Chrome时告诉我那里的滚动也很流畅。

我想我的问题可以通过浏览器x操作系统列表来回答,这些浏览器需要JavaScript滚动增强(我不能访问所有浏览器),或者通过改进我的代码来避免在不需要增强的浏览器下出现丑陋的行为。

所需功能包括:

  • 无需jQuery
  • 平滑的上/下键滚动
  • 滚动div,不仅限于主窗口
  • 无需jQuery(这对我很重要,因此我提到了两次)
  • 无MooTools、无框架,只使用原生JS(也许可以接受Modernizr或其他简洁的工具)

任何关于代码的建议也将不胜感激(我知道我应该尽快使用requestAnimationFrame)

目前,我的代码如下:

// easeOutQuad by Robert Penner
Math.easeOut = function (t, b, c, d) { t /= d; return -c * t*(t-2) + b; };

(function() { // do not mess global space
var
  interval, // scroll is being eased
  mult = 0, // how fast do we scroll
  dir = 0, // 1 = scroll down, -1 = scroll up
  steps = 50, // how many steps in animation
  length = 30, // how long to animate
  keyDelta = 0;
function KeyWheelHandler(e) {
  if(e.which!=38 && e.which!=40) return;
  keyDelta = e.which==38 ? -1 : 1;
  mult = 4;
  MouseWheelHandler(e);
}
function MouseWheelHandler(e) {
  e.preventDefault(); // prevent default browser scroll
  clearInterval(interval); // cancel previous animation
  ++mult; // we are going to scroll faster
  var delta = keyDelta || -Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
  if(dir!=delta) { // scroll direction changed
    if(!keyDelta) mult = 1; // start slowly
    dir = delta;
  }
  // get the closest scrollable parent
  for(var tgt=e.target; tgt!=document.documentElement; tgt=tgt.parentNode) {
    var oldScroll = tgt.scrollTop;
    tgt.scrollTop+= delta;
    if(oldScroll!=tgt.scrollTop) break;
  }
  var start = tgt.scrollTop;
  var end = start + length*mult*delta; // where to end the scroll
  var change = end - start; // base change in one step
  var step = 2; // current step, not less than 2, see the (t-2) in EaseOut
  interval = setInterval(function() {
    var pos = Math.easeOut(step++,start,change,steps);
    tgt.scrollTop = pos;
    if(step>=steps) { // scroll finished without speed up - stop
      mult = keyDelta = 0;
      clearInterval(interval);
    }
  },15);
}
if(window.chrome) { // Opera and Chrome
  window.addEventListener("mousewheel", MouseWheelHandler);
  //window.addEventListener("DOMMouseScroll", MouseWheelHandler); // FF
  document.documentElement.addEventListener("keydown", KeyWheelHandler);
}
})();

我会把wheel事件用作默认事件,因为它是现代跨浏览器版本。顺便说一下,看起来你没有在监听器中传递事件,因此使用该部分的函数将无法工作。 - Shikkediel
未传递事件?您能否指出具体是哪里? - Jan Turoň
window.addEventListener("mousewheel", MouseWheelHandler); - Shikkediel
MouseWheelHandler函数本身像其他函数一样需要将e作为参数传入... - Shikkediel
当然,e 是通过系统调用传递的(除了旧版的 Explorer)。如果我漏掉了什么,请在代码中用注释回答。如果您有更好的解决方案,可以在这里回答,最好附上权威参考链接。 - Jan Turoň
1个回答

0

看起来在未来(截至2015年)css smooth-scroll将解决这个问题:

滚动框以用户代理定义的时间函数平稳地滚动,在用户代理定义的一段时间内。如果有任何平台规定,用户代理应该遵循它们。

用户代理可能会忽略此属性。(???)

关于忽略的注意事项可能是浏览器大多数情况下都忽略它的原因,但Chrome正在处理它,所以我期望Opera也会在后面实现它。

IE、FF和Safari的最新版本似乎在任何地方默认平稳滚动,因此可以通过等待来解决这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接