首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何平滑地滚动到纯JavaScript中的元素

如何平滑地滚动到纯JavaScript中的元素
EN

Stack Overflow用户
提问于 2018-08-05 05:23:00
回答 4查看 29.8K关注 0票数 20

我想在不使用jQuery的情况下平滑地滚动到一个元素--只使用纯javascript。我希望一个通用的功能,能够顺利地向下滚动和向上滚动到文档中的特定位置。

我知道我可以在jQuery中使用以下内容:

代码语言:javascript
复制
$('html, body').animate({
     scrollTop: $('#myelementid').offset().top
}, 500);

如果只用javascript我该怎么做呢?

这就是我想要做的:

代码语言:javascript
复制
function scrollToHalf(){
  //what do I do?
}
function scrollToSection(){
 //What should I do here?
}
代码语言:javascript
复制
<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中,我会这样做:

代码语言:javascript
复制
html, body{
  height: 3000px;
}
代码语言:javascript
复制
<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解决方案)

EN

回答 4

Stack Overflow用户

发布于 2018-08-05 05:23:25

要在一段精确的时间内滚动到某个位置,可以使用window.requestAnimationFrame,每次计算相应的当前位置。当不支持requestAnimationFrame时,可以使用setTimeout来达到类似的效果。

代码语言:javascript
复制
/*
   @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);
        }
    });
}

演示:

代码语言:javascript
复制
/*
   @param time: the exact amount of time the scrolling will take (in milliseconds)
   @param pos: the y-position to scroll to (in pixels)
*/
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);
        }
    });
}
代码语言:javascript
复制
<button onClick="scrollToSmoothly(document.querySelector('div').offsetTop, 300)">
Scroll To Div (300ms)
</button>
<button onClick="scrollToSmoothly(document.querySelector('div').offsetTop, 200)">
Scroll To Div (200ms)
</button>
<button onClick="scrollToSmoothly(document.querySelector('div').offsetTop, 100)">
Scroll To Div (100ms)
</button>
<button onClick="scrollToSmoothly(document.querySelector('div').offsetTop, 50)">
Scroll To Div (50ms)
</button>
<button onClick="scrollToSmoothly(document.querySelector('div').offsetTop, 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>

对于更复杂的情况,可以使用SmoothScroll.js library,它可以处理垂直和水平平滑滚动、在其他容器元素内滚动、不同的缓动行为、从当前位置相对滚动等。

代码语言:javascript
复制
var easings = document.getElementById("easings");
for(var key in smoothScroll.easing){
    if(smoothScroll.easing.hasOwnProperty(key)){
        var option = document.createElement('option');
        option.text = option.value = key;
        easings.add(option);
    }
}
document.getElementById('to-bottom').addEventListener('click', function(e){
    smoothScroll({yPos: 'end', easing: easings.value, duration: 2000});
});
document.getElementById('to-top').addEventListener('click', function(e){
    smoothScroll({yPos: 'start', easing: easings.value, duration: 2000});
});
代码语言:javascript
复制
<script src="https://cdn.jsdelivr.net/gh/LieutenantPeacock/SmoothScroll@1.2.0/src/smoothscroll.min.js" integrity="sha384-UdJHYJK9eDBy7vML0TvJGlCpvrJhCuOPGTc7tHbA+jHEgCgjWpPbmMvmd/2bzdXU" crossorigin="anonymous"></script>
<!-- Taken from one of the library examples -->
Easing: <select id="easings"></select>
<button id="to-bottom">Scroll To Bottom</button>
<br>
<button id="to-top" style="margin-top: 5000px;">Scroll To Top</button>

或者,可以将options对象传递给window.scrollwindow.scrollBy,前者滚动到特定的x和y位置,后者从当前位置滚动一定数量:

代码语言:javascript
复制
// 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' 
});

演示:

代码语言:javascript
复制
<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

代码语言:javascript
复制
document.getElementById("elemID").scrollIntoView({ 
  behavior: 'smooth' 
});

演示:

代码语言:javascript
复制
<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 property,它可用于使文档中的滚动变得平滑(不需要JavaScript)。锚标签可以通过给锚标签一个#href加上要滚动到的元素的id )来实现这一点。您还可以为特定容器(如div )设置scroll-behavior属性,以使其内容平滑滚动。

演示:

代码语言:javascript
复制
html, body{
  scroll-behavior: smooth;
}
a, a:visited{
  color: initial;
}
代码语言:javascript
复制
<a href="#elem">Scroll To Element</a>
<div id="elem" style="margin: 500px 0px;">Div</div>

在使用JavaScript时,CSS scroll-behavior属性也适用于window.scrollTo

演示:

代码语言:javascript
复制
html, body{
  scroll-behavior: smooth;
}
代码语言:javascript
复制
<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>

若要检查是否支持scroll-behavior属性,可以检查它是否作为HTML元素的样式中的键存在。

代码语言:javascript
复制
var scrollBehaviorSupported = 'scroll-behavior' in document.documentElement.style;
console.log('scroll-behavior supported:', scrollBehaviorSupported);

票数 37
EN

Stack Overflow用户

发布于 2018-08-05 05:27:25

票数 3
EN

Stack Overflow用户

发布于 2018-08-05 07:56:26

正如我在评论中提到的,当您试图滚动到指定的元素时,scrollIntoView是一个很好的选择--它会得到越来越多的浏览器支持--比如您显然想要对scrollToSection函数做什么。

要滚动到页面中间,可以将body和/或html元素的scrollTop属性设置为body的scrollHeight和窗口的innerHeight之差的一半。把上面的计算和requestAnimationFrame结合起来,你就完成了。

下面是如何将上述建议合并到您的代码中:

代码语言:javascript
复制
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"});
}
代码语言:javascript
复制
#section1 {
  margin: 1000px 0;
  border: 1px solid red
}
代码语言:javascript
复制
<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>

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51689653

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档