我想不使用jQuery(仅使用纯JavaScript)即可平滑滚动至某个元素。我希望通用函数既可以向下滚动又可以向上平滑滚动到文档中的特定位置。
我知道我可以在jQuery中使用以下内容:
$('html, body').animate({
scrollTop: $('#myelementid').offset().top
}, 500);
仅使用JavaScript怎么办?
这就是我想要做的:
function scrollToHalf(){
//what do I do?
}
function scrollToSection(){
//What should I do here?
}
<input type="button" onClick="scrollToHalf()" value="Scroll To 50% of Page">
<br>
<input type="button" onClick="scrollToSection()" value="Scroll To Section1">
<section style="margin-top: 1000px;" id="section1">
This is a section
</section>
在jquery中,我会这样做:
html, body{
height: 3000px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="button" onClick="scrollToHalf()" value="Scroll To 50% of Page">
<br>
<input type="button" onClick="scrollToSection()" value="Scroll To Section1">
<section style="margin-top: 1000px;" id="section1">
This is a section
</section>
<script>
function scrollToHalf(){
var height = $('body').height();
$('html, body').animate({
scrollTop: height/2
}, 500);
}
function scrollToSection(){
$('html, body').animate({
scrollTop: $('#section1').offset().top
}, 500);
}
</script>
编辑:我还希望能够平滑滚动到页面上的某个位置
编辑:也欢迎CSS解决方案(尽管我更喜欢javascript解决方案)
答案 0 :(得分:14)
您可以对for
和window.scrollTo
使用setTimeout
循环,以使用纯Javascript平滑滚动。要滚动到特定元素,只需使用元素的offsetTop作为第一个参数调用scrollToSmoothly
函数即可。
function scrollToSmoothly(pos, time) {
/*Time is only applicable for scrolling upwards*/
/*Code written by hev1*/
/*pos is the y-position to scroll to (in pixels)*/
if (isNaN(pos)) {
throw "Position must be a number";
}
if (pos < 0) {
throw "Position can not be negative";
}
var currentPos = window.scrollY || window.screenTop;
if (currentPos < pos) {
var t = 10;
for (let i = currentPos; i <= pos; i += 10) {
t += 10;
setTimeout(function() {
window.scrollTo(0, i);
}, t / 2);
}
} else {
time = time || 2;
var i = currentPos;
var x;
x = setInterval(function() {
window.scrollTo(0, i);
i -= 10;
if (i <= pos) {
clearInterval(x);
}
}, time);
}
}
演示:
<button onClick="scrollToDiv()">Scroll To Element</button>
<div style="margin: 1000px 0px; text-align: center;">Div element<p/>
<button onClick="scrollToSmoothly(Number(0))">Scroll back to top</button>
<p/>
<button onClick="scrollToSmoothly(document.body.offsetHeight)">
Scroll To Bottom
</button>
</div>
<button onClick="scrollToSmoothly(Number(500))">
Scroll to y-position 500px
</button>
<script>
function scrollToSmoothly(pos, time){
/*Time is only applicable for scrolling upwards*/
/*Code written by hev1*/
/*pos is the y-position to scroll to (in pixels)*/
if(isNaN(pos)){
throw "Position must be a number";
}
if(pos<0){
throw "Position can not be negative";
}
var currentPos = window.scrollY||window.screenTop;
if(currentPos<pos){
if(time){
var x;
var i = currentPos;
x = setInterval(function(){
window.scrollTo(0, i);
i += 10;
if(i>=pos){
clearInterval(x);
}
}, time);
} else {
var t = 10;
for(let i = currentPos; i <= pos; i+=10){
t+=10;
setTimeout(function(){
window.scrollTo(0, i);
}, t/2);
}
}
} else {
time = time || 2;
var i = currentPos;
var x;
x = setInterval(function(){
window.scrollTo(0, i);
i -= 10;
if(i<=pos){
clearInterval(x);
}
}, time);
}
}
function scrollToDiv(){
var elem = document.querySelector("div");
scrollToSmoothly(elem.offsetTop);
}
</script>
要在确切的时间内滚动到某个位置,可以使用window.requestAnimationFrame
。 JSFiddle WebPage演示:http://jsfiddle.net/4xwnzgj5/embedded/result
function scrollToSmoothly(pos, time){
/*Time is exact amount of time the scrolling will take (in milliseconds)*/
/*Pos is the y-position to scroll to (in pixels)*/
/*Code written by hev1*/
if(typeof pos!== "number"){
pos = parseFloat(pos);
}
if(isNaN(pos)){
console.warn("Position must be a number or a numeric String.");
throw "Position must be a number";
}
if(pos<0||time<0){
return;
}
var currentPos = window.scrollY || window.screenTop;
var start = null;
time = time || 500;
window.requestAnimationFrame(function step(currentTime){
start = !start? currentTime: start;
if(currentPos<pos){
var progress = currentTime - start;
window.scrollTo(0, ((pos-currentPos)*progress/time)+currentPos);
if(progress < time){
window.requestAnimationFrame(step);
} else {
window.scrollTo(0, pos);
}
} else {
var progress = currentTime - start;
window.scrollTo(0, currentPos-((currentPos-pos)*progress/time));
if(progress < time){
window.requestAnimationFrame(step);
} else {
window.scrollTo(0, pos);
}
}
});
}
演示:
<button onClick="scrollToSmoothly(Number(document.querySelector('div').offsetTop), Number(300))">
Scroll To Div (300ms)
</button>
<button onClick="scrollToSmoothly(Number(document.querySelector('div').offsetTop), Number(200))">
Scroll To Div (200ms)
</button>
<button onClick="scrollToSmoothly(Number(document.querySelector('div').offsetTop), Number(100))">
Scroll To Div (100ms)
</button>
<button onClick="scrollToSmoothly(Number(document.querySelector('div').offsetTop), 50)">
Scroll To Div (50ms)
</button>
<button onClick="scrollToSmoothly(Number(document.querySelector('div').offsetTop), Number(1000))">
Scroll To Div (1000ms)
</button>
<div style="margin: 500px 0px;">
DIV<p/>
<button onClick="scrollToSmoothly(0, 500)">
Back To Top
</button>
<button onClick="scrollToSmoothly(document.body.scrollHeight)">
Scroll To Bottom
</button>
</div>
<div style="margin: 500px 0px;">
</div>
<button style="margin-top: 100px;" onClick="scrollToSmoothly(500, 3000)">
Scroll To y-position 500px (3000ms)
</button>
<script>
function scrollToSmoothly(pos, time){
/*Time is exact amount of time the scrolling will take (in milliseconds)*/
/*Pos is the y-position to scroll to (in pixels)*/
/*Code written by hev1*/
if(typeof pos!== "number"){
pos = parseFloat(pos);
}
if(isNaN(pos)){
console.warn("Position must be a number or a numeric String.");
throw "Position must be a number";
}
if(pos<0||time<0){
return;
}
var currentPos = window.scrollY || window.screenTop;
var start = null;
time = time || 500;
window.requestAnimationFrame(function step(currentTime){
start = !start? currentTime: start;
if(currentPos<pos){
var progress = currentTime - start;
window.scrollTo(0, ((pos-currentPos)*progress/time)+currentPos);
if(progress < time){
window.requestAnimationFrame(step);
} else {
window.scrollTo(0, pos);
}
} else {
var progress = currentTime - start;
window.scrollTo(0, currentPos-((currentPos-pos)*progress/time));
if(progress < time){
window.requestAnimationFrame(step);
} else {
window.scrollTo(0, pos);
}
}
});
}
</script>
或者,您可以使用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'
});
演示:
<button onClick="scrollToDiv()">Scroll To Element</button>
<div style="margin: 500px 0px;">Div</div>
<script>
function scrollToDiv(){
var elem = document.querySelector("div");
window.scroll({
top: elem.offsetTop,
left: 0,
behavior: 'smooth'
});
}
</script>
如果仅需要滚动到元素,而不是文档中的特定位置,则可以将Element.scrollIntoView
设置为behavior
的情况下使用smooth
。
document.getElementById("elemID").scrollIntoView({
behavior: 'smooth'
});
演示:
<button onClick="scrollToDiv()">Scroll To Element</button>
<div id="myDiv" style="margin: 500px 0px;">Div</div>
<script>
function scrollToDiv(){
document.getElementById("myDiv").scrollIntoView({
behavior: 'smooth'
});
}
</script>
现代浏览器支持scroll-behavior
CSS属性,该属性可用于使文档平滑滚动(无需Java脚本;可通过为锚标记提供{{1})来使用锚标记。 href
的}加上要滚动到的元素的#
。您还可以为诸如id
之类的特定元素设置scroll-behavior
属性,以使其内容平滑滚动。
演示:
div
html, body{
scroll-behavior: smooth;
}
a, a:visited{
color: initial;
}
使用<a href="#elem">Scroll To Element</a>
<div id="elem" style="margin: 500px 0px;">Div</div>
时,CSS scroll-behavior
属性也可以与Javascript一起使用。
演示:
window.scrollTo
html, body{
scroll-behavior: smooth;
}
要检查<button onClick="scrollToDiv()">Scroll To Element</button>
<div style="margin: 500px 0px;">Div</div>
<script>
function scrollToDiv(){
var elem = document.querySelector("div");
window.scrollTo(0, elem.offsetTop);
}
</script>
属性是否受支持,可以检查该属性是否作为HTML元素样式的键存在。
scroll-behavior
答案 1 :(得分:1)
答案 2 :(得分:1)
正如我在评论中提到的,scrollIntoView
是一个不错的选择,可以在您尝试滚动到指定元素(例如您显然要使用的元素)时获得越来越大的浏览器支持。 scrollToSection
功能。
要滚动到页面中间,可以将scrollTop
和{或body
元素的html
属性设置为scrollHeight
的一半正文和窗口的innerHeight
。将以上计算与requestAnimationFrame
结合起来,您就设置好了。
以下是将上述建议合并到代码中的方法:
function scrollToHalf(duration) {
var
heightDiff = document.body.scrollHeight - window.innerHeight,
endValue = heightDiff / 2,
start = null;
/* Set a default for the duration, in case it's not given. */
duration = duration || 300;
/* Start the animation. */
window.requestAnimationFrame(function step (now) {
/* Normalise the start date and calculate the current progress. */
start = !start ? now : start;
var progress = now - start;
/* Increment by a calculate step the value of the scroll top. */
document.documentElement.scrollTop = endValue * progress / duration;
document.body.scrollTop = endValue * progress / duration;
/* Check whether the current progress is less than the given duration. */
if (progress < duration) {
/* Execute the function recursively. */
window.requestAnimationFrame(step);
}
else {
/* Set the scroll top to the end value. */
document.documentElement.scrollTop = endValue;
document.body.scrollTop = endValue;
}
});
}
function scrollToSection(element) {
/* Scroll until the button's next sibling comes into view. */
element.nextElementSibling.scrollIntoView({block: "start", behavior: "smooth"});
}
#section1 {
margin: 1000px 0;
border: 1px solid red
}
<input type="button" onClick="scrollToHalf()" value="Scroll To 50% of Page">
<br>
<input type="button" onClick="scrollToSection(this)" value="Scroll To Section1">
<section id="section1">
This is a section
</section>
答案 3 :(得分:1)
您可以使用以下简单的polyfill滚动所需的任何节点对象:
Node.prototype.scroll = window.scroll
它将为您提供滚动对象的相同访问权限,但是对于任何DOM元素,您都可以像这样使用它:
document.querySelector('.scrollable-div').scroll({
top: 500,
left: 0,
behavior: 'smooth'
});
答案 4 :(得分:0)
这个问题已经有很多答案了,但是我想我可以分享一下我的用处。
以下使您可以在指定的时间内平滑滚动到页面上的任何位置,上下或向下。我不确定它是否与每个浏览器兼容,但我很确定它是否兼容。 (如果我错了,请纠正我。)
重要修改:确保CSS中没有html {scroll-behavior: smooth;}
。否则,这将无法正常工作。
function scrollToInTime(element, duration) {
const endPoint = document.querySelector(element).offsetTop,
distance = endPoint - window.pageYOffset,
rate = (distance * 4) / duration, // px/4ms
interval = setInterval(scrollIncrement, 4) //4ms is minimum interval for browser
function scrollIncrement() {
const yOffset = Math.ceil(window.pageYOffset)
if (
(yOffset >= endPoint && rate >= 0) ||
(yOffset <= endPoint && rate <= 0)
) {
clearInterval(interval)
} else {
//keep in mind that scrollBy doesn't work with decimal pixels < 1 like 0.4px, so
//if duration is too big, function won't work. rate must end up being >= 1px
window.scrollBy(0, rate)
}
}
}
以下是一个codepen作为示例:https://codepen.io/isaac-svi/pen/xxZgPZp?editors=0110
答案 5 :(得分:0)
使用此 CSS 属性可以将滚动行为切换为平滑。
html {
scroll-behavior: smooth;
}
这也将通过哈希 <a href="#about">
平滑滚动默认 html 导航到 <section id="about">
,这里不需要 js。
如果您想为滚动添加自己的逻辑,请考虑此示例
在这里,我不是直接滚动到滚动目标元素,而是考虑到固定的标题高度高 90 像素。
TL;博士
document.querySelectorAll("nav a").forEach(function (a) {
a.addEventListener("click", function (event) {
event.preventDefault();
const hash = event.target.getAttribute("href");
const scrollTarget = document.querySelector(hash);
// Some additional logic
const headerHeight = 90;
window.scrollTo(0, scrollTarget.offsetTop - headerHeight);
});
});