Javascript 滾動

2023-02-17 10:55 更新

?scroll? 事件允許對頁面或元素滾動作出反應(yīng)。我們可以在這里做一些有用的事情。

例如:

  • 根據(jù)用戶在文檔中的位置顯示/隱藏其他控件或信息。
  • 當(dāng)用戶向下滾動到頁面末端時加載更多數(shù)據(jù)。

這是一個顯示當(dāng)前滾動的小函數(shù):

window.addEventListener('scroll', function() {
  document.getElementById('showScroll').innerHTML = window.pageYOffset + 'px';
});

在運行中:

Current scroll = scroll the window

scroll 事件在 window 和可滾動元素上都可以運行。

防止?jié)L動

我們?nèi)绾问鼓承〇|西變成不可滾動?

我們不能通過在 onscroll 監(jiān)聽器中使用 event.preventDefault() 來阻止?jié)L動,因為它會在滾動發(fā)生 之后 才觸發(fā)。

但是我們可以在導(dǎo)致滾動的事件上,例如在 pageUp 和 pageDown 的 keydown 事件上,使用 event.preventDefault() 來阻止?jié)L動。

如果我們向這些事件中添加事件處理程序,并向其中添加 event.preventDefault(),那么滾動就不會開始。

啟動滾動的方式有很多,使用 CSS 的 overflow 屬性更加可靠。

有幾個練習(xí)題,你可以解決或者瀏覽以下幾個任務(wù)來看一下 onscroll 的應(yīng)用。

任務(wù)


無限的頁面

重要程度: 5

創(chuàng)建一個無限的頁面。當(dāng)訪問者滾動到頁面末端時,它會自動將當(dāng)期日期時間附加到文本中(以便訪問者可以滾動更多內(nèi)容)。

請注意滾動的兩個重要特性:

  1. 滾動是“彈性的”。在某些瀏覽器/設(shè)備中,我們可以在文檔的頂端或末端稍微多滾動出一點(超出部分顯示的是空白區(qū)域,然后文檔將自動“彈回”到正常狀態(tài))。
  2. 滾動并不精確。當(dāng)我們滾動到頁面末端時,實際上我們可能距真實的文檔末端約 0-50px。

因此,“滾動到末端”應(yīng)該意味著訪問者離文檔末端的距離不超過 100px。

P.S. 在現(xiàn)實生活中,我們可能希望顯示“更多信息”或“更多商品”。

打開一個任務(wù)沙箱。


解決方案

解決方案的核心是一個函數(shù),當(dāng)我們在頁面末端時,該函數(shù)可以向頁面添加更多日期(或者在實際開發(fā)中是加載更多內(nèi)容)。

我們可以立即調(diào)用它,并將其添加為 window.onscroll 處理程序。

最重要的問題是:“如何檢測頁面滾動到了末端?”

讓我們使用相對于窗口的坐標(biāo)。

文檔(document)在 <html> 標(biāo)簽中被表示(被包含)為 document.documentElement

我們可以通過 document.documentElement.getBoundingClientRect() 來獲取整個文檔相對于窗口的坐標(biāo)。bottom 屬性將是文檔末端的相對于窗口的坐標(biāo)。

例如,如果整個 HTML 文檔的高度是 2000px,那么:

// 當(dāng)我們在頁面頂端時
// 相對于窗口 top = 0
document.documentElement.getBoundingClientRect().top = 0

// 相對于窗口 bottom = 2000
// 如果文檔太長,那么可能會遠遠超出窗口底部
document.documentElement.getBoundingClientRect().bottom = 2000

如果我們向下滾動 500px,那么:

// 文檔頂端在窗口之方 500px
document.documentElement.getBoundingClientRect().top = -500
// 文檔末端相對于窗口近了 500px
document.documentElement.getBoundingClientRect().bottom = 1500

當(dāng)我們滾動到文檔末端時,假設(shè)窗口高度為 600px

// 文檔頂端在窗口上方 -1400px
document.documentElement.getBoundingClientRect().top = -1400
// 文檔末端相對于窗口坐標(biāo)為 600px
document.documentElement.getBoundingClientRect().bottom = 600

請注意,bottom 不能為 0,因為它永遠不會到達窗口頂部。bottom 坐標(biāo)的最低限度是窗口高度(我們假設(shè)其為 600),我們無法再向上滾動了。

我們可以獲得窗口的高度為 document.documentElement.clientHeight

對于本任務(wù),我們需要知道何時文檔末端距窗口底部不超過 100px(即,如果窗口高度為 600px,則為 600-700px)。

所以,函數(shù)如下:

function populate() {
  while(true) {
    // 文檔末端
    let windowRelativeBottom = document.documentElement.getBoundingClientRect().bottom;

    // 如果用戶將頁面滾動的距離不夠遠(文檔末端距窗口底部 >100px)
    if (windowRelativeBottom > document.documentElement.clientHeight + 100) break;

    // 讓我們添加更多數(shù)據(jù)
    document.body.insertAdjacentHTML("beforeend", `<p>Date: ${new Date()}</p>`);
  }
}

使用沙箱打開解決方案。


Up/down 按鈕

重要程度: 5

創(chuàng)建一個“到頂部”按鈕來幫助頁面滾動。

它應(yīng)該像這樣運行:

  • 頁面向下滾動的距離沒有超過窗口高度時 —— 按鈕不可見。
  • 當(dāng)頁面向下滾動距離超過窗口高度時 —— 在左上角出現(xiàn)一個“向上”的箭頭。如果頁面回滾回去,箭頭就會消失。
  • 單擊箭頭時,頁面將滾動到頂部。

打開一個任務(wù)沙箱。


解決方案

使用沙箱打開解決方案。


加載可視化圖像

重要程度: 4

假設(shè)我們有一個速度較慢的客戶端,并且希望節(jié)省它們在移動端的流量。

為此,我們決定不立即顯示圖像,而是將其替換為占位符,如下所示:

<img src="placeholder.svg" width="128" height="128" data-src="real.jpg">

因此,最初所有圖像均為 placeholder.svg。當(dāng)頁面滾動到用戶可以看到圖像位置時 —— 我們就會將 src 更改為 data-src 的 src,從而加載圖像。

滾動它可以看到圖像是“按需”加載的。

要求:

  • 加載頁面時,屏幕上的那些圖像應(yīng)該在滾動之前立即加載。
  • 有些圖像可能是常規(guī)圖像,沒有 ?data-src?。代碼不應(yīng)該改動它們。
  • 一旦圖像被加載,它就不應(yīng)該在滾動進/出時被重新加載。

P.S. 如果你有能力,可以創(chuàng)建一個更高級的解決方案,以“預(yù)加載”當(dāng)前位置下方/之后一頁的圖像。

P.P.S. 僅處理垂直滾動,不處理水平滾動。

打開一個任務(wù)沙箱。


解決方案

onscroll 處理程序應(yīng)該檢查哪些圖像是可見的,并顯示它們。

我們還希望在頁面加載時運行它,以檢測即將可見的圖像并加載它們。

該代碼應(yīng)該在文檔加載完成時執(zhí)行,以便可以訪問文檔內(nèi)容。

或者將該代碼放在 <body> 底部:

// ...頁面內(nèi)容在上面...

function isVisible(elem) {

  let coords = elem.getBoundingClientRect();

  let windowHeight = document.documentElement.clientHeight;

  // 頂部元素邊緣可見嗎?
  let topVisible = coords.top > 0 && coords.top < windowHeight;

  // 底部元素邊緣可見嗎?
  let bottomVisible = coords.bottom < windowHeight && coords.bottom > 0;

  return topVisible || bottomVisible;
}

showVisible() 函數(shù)使用通過 isVisible() 實現(xiàn)的可見性檢查,來加載可見圖像:

function showVisible() {
  for (let img of document.querySelectorAll('img')) {
    let realSrc = img.dataset.src;
    if (!realSrc) continue;

    if (isVisible(img)) {
      img.src = realSrc;
      img.dataset.src = '';
    }
  }
}

showVisible();
window.onscroll = showVisible;

P.S. 此解決方案還有一個 isVisible 的變體,可以“預(yù)加載”當(dāng)前文檔滾動上方/下方 1 頁內(nèi)的圖像

使用沙箱打開解決方案。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號