我正在编写一个页面,我只想将原始 JavaScript 代码用于 UI,而不受插件或框架的任何干扰。
现在我正在努力寻找一种无需 jQuery 即可平滑滚动页面的方法。
我正在编写一个页面,我只想将原始 JavaScript 代码用于 UI,而不受插件或框架的任何干扰。
现在我正在努力寻找一种无需 jQuery 即可平滑滚动页面的方法。
原生浏览器在 JavaScript 中平滑滚动是这样的:
// scroll to specific values,
// same as window.scroll() method.
// for scrolling a particular distance, use window.scrollBy().
window.scroll({
  top: 2500, 
  left: 0, 
  behavior: 'smooth' 
});
// scroll certain amounts from current position 
window.scrollBy({ 
  top: 100, // negative value acceptable
  left: 0, 
  behavior: 'smooth' 
});
// scroll to a certain element
document.querySelector('.hello').scrollIntoView({ 
  behavior: 'smooth' 
});
试试这个平滑滚动演示,或者像这样的算法:
self.pageYOffsetelement.offsetTopwindow.scrollTo另请参阅此问题的另一个流行答案。
安德鲁约翰逊的原始代码:
function currentYPosition() {
    // Firefox, Chrome, Opera, Safari
    if (self.pageYOffset) return self.pageYOffset;
    // Internet Explorer 6 - standards mode
    if (document.documentElement && document.documentElement.scrollTop)
        return document.documentElement.scrollTop;
    // Internet Explorer 6, 7 and 8
    if (document.body.scrollTop) return document.body.scrollTop;
    return 0;
}
function elmYPosition(eID) {
    var elm = document.getElementById(eID);
    var y = elm.offsetTop;
    var node = elm;
    while (node.offsetParent && node.offsetParent != document.body) {
        node = node.offsetParent;
        y += node.offsetTop;
    } return y;
}
function smoothScroll(eID) {
    var startY = currentYPosition();
    var stopY = elmYPosition(eID);
    var distance = stopY > startY ? stopY - startY : startY - stopY;
    if (distance < 100) {
        scrollTo(0, stopY); return;
    }
    var speed = Math.round(distance / 100);
    if (speed >= 20) speed = 20;
    var step = Math.round(distance / 25);
    var leapY = stopY > startY ? startY + step : startY - step;
    var timer = 0;
    if (stopY > startY) {
        for ( var i=startY; i<stopY; i+=step ) {
            setTimeout("window.scrollTo(0, "+leapY+")", timer * speed);
            leapY += step; if (leapY > stopY) leapY = stopY; timer++;
        } return;
    }
    for ( var i=startY; i>stopY; i-=step ) {
        setTimeout("window.scrollTo(0, "+leapY+")", timer * speed);
        leapY -= step; if (leapY < stopY) leapY = stopY; timer++;
    }
}
相关链接:
滚动元素需要scrollTop随时间改变其值。对于给定的时间点,计算一个新scrollTop值。要平滑地制作动画,请使用平滑步长算法进行插值。
计算scrollTop如下:
var point = smooth_step(start_time, end_time, now);
var scrollTop = Math.round(start_top + (distance * point));
在哪里:
start_time 是动画开始的时间;end_time是动画结束的时间(start_time + duration);start_top是scrollTop开始时的值;和distance是期望的结束值和开始值之间的差值(target - start_top)。一个强大的解决方案应该检测动画何时被中断等等。有关详细信息,请阅读我关于没有 jQuery 的平滑滚动的文章。
请参阅JSFiddle。
代码:
/**
    Smoothly scroll element to the given target (element.scrollTop)
    for the given duration
    Returns a promise that's fulfilled when done, or rejected if
    interrupted
 */
var smooth_scroll_to = function(element, target, duration) {
    target = Math.round(target);
    duration = Math.round(duration);
    if (duration < 0) {
        return Promise.reject("bad duration");
    }
    if (duration === 0) {
        element.scrollTop = target;
        return Promise.resolve();
    }
    var start_time = Date.now();
    var end_time = start_time + duration;
    var start_top = element.scrollTop;
    var distance = target - start_top;
    // based on http://en.wikipedia.org/wiki/Smoothstep
    var smooth_step = function(start, end, point) {
        if(point <= start) { return 0; }
        if(point >= end) { return 1; }
        var x = (point - start) / (end - start); // interpolation
        return x*x*(3 - 2*x);
    }
    return new Promise(function(resolve, reject) {
        // This is to keep track of where the element's scrollTop is
        // supposed to be, based on what we're doing
        var previous_top = element.scrollTop;
        // This is like a think function from a game loop
        var scroll_frame = function() {
            if(element.scrollTop != previous_top) {
                reject("interrupted");
                return;
            }
            // set the scrollTop for this frame
            var now = Date.now();
            var point = smooth_step(start_time, end_time, now);
            var frameTop = Math.round(start_top + (distance * point));
            element.scrollTop = frameTop;
            // check if we're done!
            if(now >= end_time) {
                resolve();
                return;
            }
            // If we were supposed to scroll but didn't, then we
            // probably hit the limit, so consider it done; not
            // interrupted.
            if(element.scrollTop === previous_top
                && element.scrollTop !== frameTop) {
                resolve();
                return;
            }
            previous_top = element.scrollTop;
            // schedule next frame for execution
            setTimeout(scroll_frame, 0);
        }
        // boostrap the animation process
        setTimeout(scroll_frame, 0);
    });
}
我在这里做了一个没有 jQuery 的例子:http : //codepen.io/sorinnn/pen/ovzdq
/**
    by Nemes Ioan Sorin - not an jQuery big fan 
    therefore this script is for those who love the old clean coding style  
    @id = the id of the element who need to bring  into view
    Note : this demo scrolls about 12.700 pixels from Link1 to Link3
*/
(function()
{
      window.setTimeout = window.setTimeout; //
})();
      var smoothScr = {
      iterr : 30, // set timeout miliseconds ..decreased with 1ms for each iteration
        tm : null, //timeout local variable
      stopShow: function()
      {
        clearTimeout(this.tm); // stopp the timeout
        this.iterr = 30; // reset milisec iterator to original value
      },
      getRealTop : function (el) // helper function instead of jQuery
      {
        var elm = el; 
        var realTop = 0;
        do
        {
          realTop += elm.offsetTop;
          elm = elm.offsetParent;
        }
        while(elm);
        return realTop;
      },
      getPageScroll : function()  // helper function instead of jQuery
      {
        var pgYoff = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;
        return pgYoff;
      },
      anim : function (id) // the main func
      {
        this.stopShow(); // for click on another button or link
        var eOff, pOff, tOff, scrVal, pos, dir, step;
        eOff = document.getElementById(id).offsetTop; // element offsetTop
        tOff =  this.getRealTop(document.getElementById(id).parentNode); // terminus point 
        pOff = this.getPageScroll(); // page offsetTop
        if (pOff === null || isNaN(pOff) || pOff === 'undefined') pOff = 0;
        scrVal = eOff - pOff; // actual scroll value;
        if (scrVal > tOff) 
        {
          pos = (eOff - tOff - pOff); 
          dir = 1;
        }
        if (scrVal < tOff)
        {
          pos = (pOff + tOff) - eOff;
          dir = -1; 
        }
        if(scrVal !== tOff) 
        {
          step = ~~((pos / 4) +1) * dir;
          if(this.iterr > 1) this.iterr -= 1; 
          else this.itter = 0; // decrease the timeout timer value but not below 0
          window.scrollBy(0, step);
          this.tm = window.setTimeout(function()
          {
             smoothScr.anim(id);  
          }, this.iterr); 
        }  
        if(scrVal === tOff) 
        { 
          this.stopShow(); // reset function values
          return;
        }
    }
 }
现代浏览器支持 CSS “scroll-behavior: smooth” 属性。因此,我们甚至根本不需要任何 Javascript。只需将其添加到 body 元素,并使用常用的锚点和链接。 滚动行为 MDN 文档