簡體   English   中英

如何在純 JavaScript 中平滑滾動到元素

[英]How to smoothly scroll to an element in pure JavaScript

我想在不使用 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 解決方案)

要在精確的時間內滾動到某個位置,可以使用window.requestAnimationFrame ,每次計算適當的當前位置。 當不支持requestAnimationFrame時,可以使用setTimeout達到類似的效果。

/*
   @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);
        }
    });
}

演示:

 /* @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); } }); }
 <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 庫,它處理垂直和水平平滑滾動、在其他容器元素內部滾動、不同的緩動行為、從當前位置相對滾動等等。

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

或者,您可以將選項對象傳遞給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 屬性,可用於使文檔中的滾動平滑(無需 JavaScript)。 錨標簽可用於此目的,方法是為錨標簽提供#href加上要滾動到的元素的id )。 您還可以為特定容器(如div設置scroll-behavior屬性,以使其內容平滑滾動。

演示:

 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>

當使用window.scrollTo時,CSS scroll-behavior屬性也適用於 JavaScript。

演示:

 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>

要檢查是否支持scroll-behavior屬性,您可以檢查它是否作為 HTML 元素樣式中的鍵存在。

 var scrollBehaviorSupported = 'scroll-behavior' in document.documentElement.style; console.log('scroll-behavior supported:', scrollBehaviorSupported);

考慮使用Element.scrollIntoView()

正如我在評論中提到的,當您嘗試滾動到指定元素(例如您顯然試圖使用scrollToSection函數執行的操作)時, scrollIntoView是一個scrollIntoView考慮的不錯選擇——它獲得越來越多的瀏覽器支持。

滾動到你可以在設置頁面的中間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>

您可以使用簡單的 polyfill 滾動您想要的任何節點對象,如下所示:

Node.prototype.scroll = window.scroll

它將為您提供對滾動對象的相同訪問權限,但是對於任何 DOM 元素,您可以像這樣使用它:

document.querySelector('.scrollable-div').scroll({
  top: 500, 
  left: 0, 
  behavior: 'smooth' 
});

這個問題已經有很多答案了,但我想我可能會分享我使用的東西。

以下允許您在指定的時間內向下或向上平滑滾動到頁面上的任何位置。 我不確定它是否與所有瀏覽器兼容,但我很確定它是。 (如果我錯了,有人糾正我。)

重要編輯:確保您的 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

使用此 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);
        });
      });

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM