平滑滚动到页面上的特定元素

IT技术 javascript jquery animation scroll jquery-animate
2021-01-18 13:20:46

我想在页面的开头有 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/

6个回答

超级顺利 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/

谢谢,你最好!:)
2021-03-22 13:20:46
这是病了。谢谢!
2021-03-31 13:20:46
只是根据您的来源做一个小图书馆,在学分中链接到这里。谢谢!
2021-04-02 13:20:46
@Dev_NIX 很高兴我能帮忙!有一次我使用了Sweet-scroll库,但不知何故它在 React 中运行不佳。您可以从中重用一些 API 或代码。
2021-04-07 13:20:46

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

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

只需在您的源smoothScroll调用onClick事件函数element

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

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

第三方编辑

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

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

例如,如果网站有粘性标题,如何抵消滚动?
2021-03-14 13:20:46
@KarediaNoorsil 感谢您的报告,更新了我的答案。
2021-03-17 13:20:46
scrollIntoView with 'smooth' 不支持 IE、EDGE 和 Safari (2018/09/28)
2021-03-19 13:20:46
我认为这是最好的答案。我发现许多其他解决方案在某些移动设备上效果不佳。卡住一段时间然后开始滚动。这是唯一没有发生的。
2021-03-23 13:20:46
2020 年最佳答案。
2021-04-01 13:20:46

刚刚在下面制作了这个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);
    }
};

平滑滚动 - 看起来没有 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)

谢谢,只是节省了我一些时间:) 我还添加了smoothScroll({eID, padding = 0})然后stopY += padding;let stopY = elmYPosition(eID);元素周围有一些填充而不是滚动到确切的元素
2021-03-25 13:20:46
将字符串作为函数执行.... :( 为什么不只是: setTimeout(window.scrollTo.bind(null, 0, leapY), timer * speed);
2021-03-29 13:20:46

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

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;