Javascript 滾動(dòng)

2023-02-17 10:55 更新

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

例如:

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

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

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

在運(yùn)行中:

Current scroll = scroll the window

scroll 事件在 window 和可滾動(dòng)元素上都可以運(yùn)行。

防止?jié)L動(dòng)

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

我們不能通過在 onscroll 監(jiān)聽器中使用 event.preventDefault() 來阻止?jié)L動(dòng),因?yàn)樗鼤?huì)在滾動(dòng)發(fā)生 之后 才觸發(fā)。

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

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

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

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

任務(wù)


無限的頁面

重要程度: 5

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

請(qǐng)注意滾動(dòng)的兩個(gè)重要特性:

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

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

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

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


解決方案

解決方案的核心是一個(gè)函數(shù),當(dāng)我們?cè)陧撁婺┒藭r(shí),該函數(shù)可以向頁面添加更多日期(或者在實(shí)際開發(fā)中是加載更多內(nèi)容)。

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

最重要的問題是:“如何檢測(cè)頁面滾動(dòng)到了末端?”

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

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

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

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

// 當(dāng)我們?cè)陧撁骓敹藭r(shí)
// 相對(duì)于窗口 top = 0
document.documentElement.getBoundingClientRect().top = 0

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

如果我們向下滾動(dòng) 500px,那么:

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

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

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

請(qǐng)注意,bottom 不能為 0,因?yàn)樗肋h(yuǎn)不會(huì)到達(dá)窗口頂部。bottom 坐標(biāo)的最低限度是窗口高度(我們假設(shè)其為 600),我們無法再向上滾動(dòng)了。

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

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

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

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

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

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

使用沙箱打開解決方案。


Up/down 按鈕

重要程度: 5

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

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

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

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


解決方案

使用沙箱打開解決方案。


加載可視化圖像

重要程度: 4

假設(shè)我們有一個(gè)速度較慢的客戶端,并且希望節(jié)省它們?cè)谝苿?dòng)端的流量。

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

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

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

滾動(dòng)它可以看到圖像是“按需”加載的。

要求:

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

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

P.P.S. 僅處理垂直滾動(dòng),不處理水平滾動(dòng)。

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


解決方案

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

我們還希望在頁面加載時(shí)運(yùn)行它,以檢測(cè)即將可見的圖像并加載它們。

該代碼應(yīng)該在文檔加載完成時(shí)執(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() 實(shí)現(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. 此解決方案還有一個(gè) isVisible 的變體,可以“預(yù)加載”當(dāng)前文檔滾動(dòng)上方/下方 1 頁內(nèi)的圖像

使用沙箱打開解決方案。


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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)