45

我想在页面的开头有 4 个按钮/链接,在它们下面是内容。

在按钮上,我输入了以下代码:

<a href="#idElement1">Scroll to element 1</a>
<a href="#idElement2">Scroll to element 2</a>
<a href="#idElement3">Scroll to element 3</a>
<a href="#idElement4">Scroll to element 4</a>

在链接下会有内容:

<h2 id="idElement1">Element1</h2>
content....
<h2 id="idElement2">Element2</h2>
content....
<h2 id="idElement3">Element3</h2>
content....
<h2 id="idElement4">Element4</h2>
content....

它现在可以工作,但不能让它看起来更流畅。

我使用了此代码,但无法使其正常工作。

$('html, body').animate({
    scrollTop: $("#elementID").offset().top
}, 2000);

有什么建议么?谢谢你。

编辑:和小提琴:http: //jsfiddle.net/WxJLx/2/

4

12 回答 12

95

超级顺利requestAnimationFrame

对于平滑渲染的滚动动画,可以使用window.requestAnimationFrame()比常规解决方案更好的渲染效果setTimeout()

一个基本示例如下所示。浏览器的每个动画帧都会调用该函数step,并允许更好地管理重绘时间,从而提高性能。

function doScrolling(elementY, duration) { 
  var startingY = window.pageYOffset;
  var diff = elementY - startingY;
  var start;

  // Bootstrap our animation - it will get called right before next frame shall be rendered.
  window.requestAnimationFrame(function step(timestamp) {
    if (!start) start = timestamp;
    // Elapsed milliseconds since start of scrolling.
    var time = timestamp - start;
    // Get percent of completion in range [0, 1].
    var percent = Math.min(time / duration, 1);

    window.scrollTo(0, startingY + diff * percent);

    // Proceed with animation as long as we wanted it to.
    if (time < duration) {
      window.requestAnimationFrame(step);
    }
  })
}

对于元素的 Y 位置,请使用其他答案中的函数或我下面提到的小提琴中的函数。

我设置了一个更复杂的功能,支持缓和并正确滚动到最底部的元素: https ://jsfiddle.net/s61x7c4e/

于 2016-09-14T15:25:09.530 回答
79

5 年前有人问过这个问题,我正在处理这个问题,smooth scroll觉得给那些正在寻找的人提供一个简单的解决方案是值得的。所有的答案都很好,但在这里你去一个简单的。

function smoothScroll(){
    document.querySelector('.your_class or #id here').scrollIntoView({
        behavior: 'smooth'
    });
}

只需在源上的事件上调用smoothScroll函数。onClickelement

文档:https ://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView

注意:请在此处检查兼容性

第三方编辑

2020 年的支持Element.scrollIntoView()是这样的:

Region            full   + partial = sum full+partial Support
Asia              73.24% + 22.75%  = 95.98%
North America     56.15% + 42.09%  = 98.25%
India             71.01% + 20.13%  = 91.14%
Europe            68.58% + 27.76%  = 96.35%

scrollintoview 支持 2020-02-28

于 2018-08-13T06:40:15.030 回答
30

刚刚在下面制作了这个仅限javascript的解决方案。

简单用法:

EPPZScrollTo.scrollVerticalToElementById('signup_form', 20);

引擎对象(您可以摆弄过滤器、fps 值):

/**
 *
 * Created by Borbás Geri on 12/17/13
 * Copyright (c) 2013 eppz! development, LLC.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */


var EPPZScrollTo =
{
    /**
     * Helpers.
     */
    documentVerticalScrollPosition: function()
    {
        if (self.pageYOffset) return self.pageYOffset; // Firefox, Chrome, Opera, Safari.
        if (document.documentElement && document.documentElement.scrollTop) return document.documentElement.scrollTop; // Internet Explorer 6 (standards mode).
        if (document.body.scrollTop) return document.body.scrollTop; // Internet Explorer 6, 7 and 8.
        return 0; // None of the above.
    },

    viewportHeight: function()
    { return (document.compatMode === "CSS1Compat") ? document.documentElement.clientHeight : document.body.clientHeight; },

    documentHeight: function()
    { return (document.height !== undefined) ? document.height : document.body.offsetHeight; },

    documentMaximumScrollPosition: function()
    { return this.documentHeight() - this.viewportHeight(); },

    elementVerticalClientPositionById: function(id)
    {
        var element = document.getElementById(id);
        var rectangle = element.getBoundingClientRect();
        return rectangle.top;
    },

    /**
     * Animation tick.
     */
    scrollVerticalTickToPosition: function(currentPosition, targetPosition)
    {
        var filter = 0.2;
        var fps = 60;
        var difference = parseFloat(targetPosition) - parseFloat(currentPosition);

        // Snap, then stop if arrived.
        var arrived = (Math.abs(difference) <= 0.5);
        if (arrived)
        {
            // Apply target.
            scrollTo(0.0, targetPosition);
            return;
        }

        // Filtered position.
        currentPosition = (parseFloat(currentPosition) * (1.0 - filter)) + (parseFloat(targetPosition) * filter);

        // Apply target.
        scrollTo(0.0, Math.round(currentPosition));

        // Schedule next tick.
        setTimeout("EPPZScrollTo.scrollVerticalTickToPosition("+currentPosition+", "+targetPosition+")", (1000 / fps));
    },

    /**
     * For public use.
     *
     * @param id The id of the element to scroll to.
     * @param padding Top padding to apply above element.
     */
    scrollVerticalToElementById: function(id, padding)
    {
        var element = document.getElementById(id);
        if (element == null)
        {
            console.warn('Cannot find element with id \''+id+'\'.');
            return;
        }

        var targetPosition = this.documentVerticalScrollPosition() + this.elementVerticalClientPositionById(id) - padding;
        var currentPosition = this.documentVerticalScrollPosition();

        // Clamp.
        var maximumScrollPosition = this.documentMaximumScrollPosition();
        if (targetPosition > maximumScrollPosition) targetPosition = maximumScrollPosition;

        // Start animation.
        this.scrollVerticalTickToPosition(currentPosition, targetPosition);
    }
};
于 2013-12-18T23:30:18.973 回答
21

平滑滚动 - 看起来不像 jQuery

根据itnewb.com 上的一篇文章,我做了一个演示 plunk,无需外部库 即可顺利滚动。

javascript非常简单。首先是一个帮助函数来改进跨浏览器支持来确定当前位置。

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++;
    }
    return false;
}

要调用它,您只需执行以下操作。您可以使用 id 作为目标锚点的参考来创建指向另一个元素的链接。

<a href="#anchor-2" 
   onclick="smoothScroll('anchor-2');">smooth scroll to the headline with id anchor-2<a/>
...
...  some content
...
<h2 id="anchor-2">Anchor 2</h2>

版权

在 itnewb.com 的页脚中写了以下内容:The techniques, effects and code demonstrated in ITNewb articles may be used for any purpose without attribution (although we recommend it)(2014-01-12)

于 2013-07-18T18:58:37.563 回答
11

您还可以查看这个很棒的博客 - 用一些非常简单的方法来实现这一点:)

https://css-tricks.com/snippets/jquery/smooth-scrolling/

喜欢(来自博客)

// Scroll to specific values
// scrollTo is the same
window.scroll({
  top: 2500, 
  left: 0, 
  behavior: 'smooth'
});

// Scroll certain amounts from current position 
window.scrollBy({ 
  top: 100, // could be negative value
  left: 0, 
  behavior: 'smooth' 
});

// Scroll to a certain element
document.querySelector('.hello').scrollIntoView({ 
  behavior: 'smooth' 
});

并且您还可以获得元素“顶部”位置,如下所示(或其他方式)

var e = document.getElementById(element);
var top = 0;

do {   
    top += e.offsetTop;
} while (e = e.offsetParent);

return top;
于 2019-05-16T08:51:09.923 回答
8

为什么不使用 CSS滚动行为属性

html {
  scroll-behavior: smooth;
}

浏览器支持也不错 https://caniuse.com/#feat=css-scroll-behavior

于 2020-05-09T05:09:54.350 回答
5

我已经使用了很长时间:

function scrollToItem(item) {
    var diff=(item.offsetTop-window.scrollY)/8
    if (Math.abs(diff)>1) {
        window.scrollTo(0, (window.scrollY+diff))
        clearTimeout(window._TO)
        window._TO=setTimeout(scrollToItem, 30, item)
    } else {
        window.scrollTo(0, item.offsetTop)
    }
}

用法: 例如在scrollToItem(element)哪里。elementdocument.getElementById('elementid')

于 2016-07-05T14:44:53.520 回答
4

@tominko 答案的变体。当某些元素无法与视口顶部对齐时,动画更流畅一些并解决了无限调用 setTimeout() 的问题。

function scrollToItem(item) {
    var diff=(item.offsetTop-window.scrollY)/20;
    if(!window._lastDiff){
        window._lastDiff = 0;
    }

    console.log('test')

    if (Math.abs(diff)>2) {
        window.scrollTo(0, (window.scrollY+diff))
        clearTimeout(window._TO)

        if(diff !== window._lastDiff){
            window._lastDiff = diff;
            window._TO=setTimeout(scrollToItem, 15, item);
        }
    } else {
        console.timeEnd('test');
        window.scrollTo(0, item.offsetTop)
    }
}
于 2016-11-06T22:15:37.237 回答
4

有关平滑滚动的更全面的方法列表,请参阅我的答案here


要在准确的时间内滚动到某个位置,window.requestAnimationFrame可以使用,每次计算出合适的当前位置。要滚动到某个元素,只需将 y 位置设置为element.offsetTop

/*
   @param pos: the y-position to scroll to (in pixels)
   @param time: the exact amount of time the scrolling will take (in milliseconds)
*/
function scrollToSmoothly(pos, time) {
    var currentPos = window.pageYOffset;
    var start = null;
    if(time == null) time = 500;
    pos = +pos, time = +time;
    window.requestAnimationFrame(function step(currentTime) {
        start = !start ? currentTime : start;
        var progress = currentTime - start;
        if (currentPos < pos) {
            window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos);
        } else {
            window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time));
        }
        if (progress < time) {
            window.requestAnimationFrame(step);
        } else {
            window.scrollTo(0, pos);
        }
    });
}

演示:

function scrollToSmoothly(pos, time) {
    var currentPos = window.pageYOffset;
    var start = null;
    if(time == null) time = 500;
    pos = +pos, time = +time;
    window.requestAnimationFrame(function step(currentTime) {
        start = !start ? currentTime : start;
        var progress = currentTime - start;
        if (currentPos < pos) {
            window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos);
        } else {
            window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time));
        }
        if (progress < time) {
            window.requestAnimationFrame(step);
        } else {
            window.scrollTo(0, pos);
        }
    });
}

document.getElementById("toElement").addEventListener("click", function(e){
  scrollToSmoothly(document.querySelector('div').offsetTop, 500 /* milliseconds */);
});
document.getElementById("backToTop").addEventListener("click", function(e){
  scrollToSmoothly(0, 500);
});
<button id="toElement">Scroll To Element</button>
<div style="margin: 1000px 0px; text-align: center;">Div element
  <button id="backToTop">Scroll back to top</button>
</div>

也可以使用SmoothScroll.js 库,它支持滚动到页面上的一个元素,此外还有更复杂的功能,例如垂直和水平平滑滚动、在其他容器元素内滚动、不同的缓动行为、从当前位置相对滚动, 和更多。

document.getElementById("toElement").addEventListener("click", function(e){
  smoothScroll({toElement: document.querySelector('div'), duration: 500});
});
document.getElementById("backToTop").addEventListener("click", function(e){
  smoothScroll({yPos: 'start', duration: 500});
});
<script src="https://cdn.jsdelivr.net/gh/LieutenantPeacock/SmoothScroll@1.2.0/src/smoothscroll.min.js" integrity="sha384-UdJHYJK9eDBy7vML0TvJGlCpvrJhCuOPGTc7tHbA+jHEgCgjWpPbmMvmd/2bzdXU" crossorigin="anonymous"></script>
<button id="toElement">Scroll To Element</button>
<div style="margin: 1000px 0px; text-align: center;">Div element
  <button id="backToTop">Scroll back to top</button>
</div>

或者,您可以传递一个选项对象,window.scroll该对象滚动到特定的 x 和 y 位置,并window.scrollBy从当前位置滚动一定量:

// Scroll to specific values
// scrollTo is the same
window.scroll({
  top: 2500, 
  left: 0, 
  behavior: 'smooth' 
});

// Scroll certain amounts from current position 
window.scrollBy({ 
  top: 100, // could be negative value
  left: 0, 
  behavior: 'smooth' 
});

如果您只需要滚动到一个元素,而不是文档中的特定位置,您可以使用Element.scrollIntoViewwith behaviorset to smooth

document.getElementById("elemID").scrollIntoView({ 
  behavior: 'smooth' 
});
于 2018-08-04T20:42:28.957 回答
2

你可以使用这个插件。做你想要的。

http://flesler.blogspot.com/2007/10/jqueryscrollto.html

于 2013-07-18T11:48:58.200 回答
0

如果需要滚动到 div 内的元素,我的解决方案是基于Andrzej Sala 的回答

function scroolTo(element, duration) {
    if (!duration) {
        duration = 700;
    }
    if (!element.offsetParent) {
        element.scrollTo();
    }
    var startingTop = element.offsetParent.scrollTop;
    var elementTop = element.offsetTop;
    var dist = elementTop - startingTop;
    var start;

    window.requestAnimationFrame(function step(timestamp) {
        if (!start)
            start = timestamp;
        var time = timestamp - start;
        var percent = Math.min(time / duration, 1);
        element.offsetParent.scrollTo(0, startingTop + dist * percent);

        // Proceed with animation as long as we wanted it to.
        if (time < duration) {
            window.requestAnimationFrame(step);
        }
    })
}
于 2018-06-25T17:54:59.790 回答
-1

使用 jQuery.ScrollTo 平滑滚动

要使用 jQuery ScrollTo 插件,您必须执行以下操作

  1. 创建href指向另一个elements.id的链接
  2. 创建要滚动到的元素
  3. 参考 jQuery 和 scrollTo 插件
  4. 确保为每个应该进行平滑滚动的链接添加一个单击事件处理程序

创建链接

<h1>Smooth Scrolling with the jQuery Plugin .scrollTo</h1>
<div id="nav-list">
  <a href="#idElement1">Scroll to element 1</a>
  <a href="#idElement2">Scroll to element 2</a>
  <a href="#idElement3">Scroll to element 3</a>
  <a href="#idElement4">Scroll to element 4</a>
</div>

在此处创建目标元素仅显示前两个,其他标题以相同方式设置。要查看另一个示例,我添加了一个返回导航的链接a.toNav

<h2 id="idElement1">Element1</h2>    
....
<h2 id="idElement1">Element1</h2>
... 
<a class="toNav" href="#nav-list">Scroll to Nav-List</a>

设置对脚本的引用。您的文件路径可能不同。

<script src="./jquery-1.8.3.min.js"></script>
<script src="./jquery.scrollTo-1.4.3.1-min.js"></script>

全部接线

下面的代码是从jQuery easing 插件中借来的

jQuery(function ($) {
    $.easing.elasout = function (x, t, b, c, d) {
        var s = 1.70158;  var p = 0; var a = c;
        if (t == 0) return b;
        if ((t /= d) == 1) return b + c;
        if (!p) p = d * .3;
        if (a < Math.abs(c)) {
            a = c;   var s = p / 4;
        } else var s = p / (2 * Math.PI) * Math.asin(c / a);
        // line breaks added to avoid scroll bar
        return a * Math.pow(2, -10 * t)  * Math.sin((t * d - s) 
                 * (2 * Math.PI) / p) + c + b;
    };            

    // important reset all scrollable panes to (0,0)       
    $('div.pane').scrollTo(0); 
    $.scrollTo(0);    // Reset the screen to (0,0)
    // adding a click handler for each link 
    // within the div with the id nav-list
    $('#nav-list a').click(function () {             
        $.scrollTo(this.hash, 1500, {
            easing: 'elasout'
        });
        return false;
    });   
    // adding a click handler for the link at the bottom
    $('a.toNav').click(function () { 
        var scrollTargetId = this.hash;
        $.scrollTo(scrollTargetId, 1500, {
            easing: 'elasout'
        });
        return false;
    });    
});

plnkr.co上的完整演示

您可以查看演示的源代码。

2014 年 5 月更新

基于另一个问题,我遇到了kadaj的另一个解决方案。这里jQuery animate用于滚动到 a 内的元素<div style=overflow-y: scroll>

 $(document).ready(function () {
    $('.navSection').on('click', function (e) {
        debugger;
        var elemId = "";    //eg: #nav2
        switch (e.target.id) {
        case "nav1":
            elemId = "#s1";
            break;
        case "nav2":
            elemId = "#s2";
            break;
        case "nav3":
            elemId = "#s3";
            break;
        case "nav4":
            elemId = "#s4";
            break;
        }
        $('.content').animate({
            scrollTop: $(elemId).parent().scrollTop() 
                    + $(elemId).offset().top 
                    - $(elemId).parent().offset().top
        }, {
            duration: 1000,
            specialEasing: { width: 'linear'
                    , height: 'easeOutBounce' },
            complete: function (e) {
                //console.log("animation completed");
            }
        });
        e.preventDefault();
    });
  });
于 2013-07-19T09:01:15.907 回答