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

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

在button上,我把这个代码:

<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); 

有什么build议么? 谢谢。

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

只是在下面的这个唯一的解决scheme。

简单的用法:

 EPPZScrollTo.scrollVerticalToElementById('signup_form', 20); 

引擎对象(你可以摆弄filter,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); } }; 

使用requestAnimationFrame超级顺畅

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

一个基本的例子是这样的。 为浏览器的每个animation帧调用functionstep ,并允许更好的重绘时间pipe理,从而提高性能。

 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 miliseconds 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/

平滑滚动 – 看起来没有jQuery

根据itnewb.com上的一篇文章,我做了一个演示程序,可以在没有外部库的情况下顺利滚动

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

 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; } 

要打电话给你,你只需要做以下的事情。 您创build一个指向另一个元素的链接,通过使用该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)

@tominko答案的变化。 一些平滑的animation和无穷调用的setTimeout()解决问题,当一些元素不能alignment到视口的顶部。

 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) } } 

我一直在使用这个很长一段时间:

 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')例如。

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

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

使用jQuery.ScrollTo平滑滚动

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

  1. 创buildhref指向另一个elements.id的链接
  2. 创build你想滚动的元素
  3. 引用jQuery和scrollTo插件
  4. 确保为每个应该平滑滚动的链接添加一个点击事件处理程序

创build链接

 <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> 

在这里创build目标元素只有前两个显示其他标题设置相同的方式。 要看到另一个例子,我添加了一个链接回到导航a.toNav

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

设置脚本的引用。 您的文件path可能会有所不同。

 <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 工作演示

你可以看看演示的soucre代码。

2014年5月更新

基于另一个问题,我遇到了 kadaj的 另一个解决scheme 。 这里使用jQuery animate来滚动到<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(); }); });