2020 年 8 月 27 日

滚动

scroll 事件允许对页面或元素滚动做出反应。我们可以在此处执行一些非常好的操作。

例如

  • 根据用户在文档中的位置显示/隐藏其他控件或信息。
  • 当用户向下滚动到页面末尾时加载更多数据。

这是一个显示当前滚动位置的小函数

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

在行动

当前滚动 = 滚动窗口

scroll 事件在 window 和可滚动元素上均可使用。

防止滚动

我们如何使某些内容不可滚动?

我们无法通过在 onscroll 侦听器中使用 event.preventDefault() 来防止滚动,因为它在滚动已经发生触发。

但是,我们可以在导致滚动的事件(例如 pageUppageDownkeydown 事件)上通过 event.preventDefault() 来防止滚动。

如果我们向这些事件添加事件处理程序并在其中使用 event.preventDefault(),那么滚动将不会开始。

有许多方法可以启动滚动,因此使用 CSS 的 overflow 属性更可靠。

以下是一些你可以解决或查看以了解 onscroll 应用的任务。

任务

重要性:5

创建一个无穷页面。当访问者将其滚动到末尾时,它会自动将当前日期时间附加到文本中(以便访问者可以滚动更多)。

像这样

请注意滚动的两个重要特性

  1. 滚动是“弹性的”。在某些浏览器/设备中,我们可以滚动到文档开始或结束之外一点(显示下面的空白,然后文档将自动“弹回”到正常状态)。
  2. 滚动不精确。当我们滚动到页面末尾时,实际上我们可能距离真正的文档底部 0-50 像素。

因此,“滚动到末尾”应该意味着访问者距离文档末尾不超过 100 像素。

P.S. 在现实生活中,我们可能希望显示“更多消息”或“更多商品”。

为任务打开沙箱。

解决方案的核心是一个函数,当我们在页面末尾时,它会向页面添加更多日期(或在现实生活中加载更多内容)。

我们可以立即调用它并将其添加为 window.onscroll 处理程序。

最重要的问题是:“我们如何检测页面是否已滚动到底部?”

让我们使用相对于窗口的坐标。

文档在 <html> 标签(即 document.documentElement)中表示(并包含)。

我们可以获取整个文档相对于窗口的坐标,即 document.documentElement.getBoundingClientRect()bottom 属性将是文档底部的相对于窗口的坐标。

例如,如果整个 HTML 文档的高度为 2000px,那么

// when we're on the top of the page
// window-relative top = 0
document.documentElement.getBoundingClientRect().top = 0

// window-relative bottom = 2000
// the document is long, so that is probably far beyond the window bottom
document.documentElement.getBoundingClientRect().bottom = 2000

如果我们向下滚动 500px,那么

// document top is above the window 500px
document.documentElement.getBoundingClientRect().top = -500
// document bottom is 500px closer
document.documentElement.getBoundingClientRect().bottom = 1500

当我们滚动到末尾时,假设窗口高度为 600px

// document top is above the window 1400px
document.documentElement.getBoundingClientRect().top = -1400
// document bottom is below the window 600px
document.documentElement.getBoundingClientRect().bottom = 600

请注意,bottom 不能为 0,因为它永远不会到达窗口顶部。bottom 坐标的最低限制是窗口高度(我们假设它是 600),我们不能再向上滚动它了。

我们可以获取窗口高度,即 document.documentElement.clientHeight

对于我们的任务,我们需要知道文档底部距离它不超过 100px(即:如果高度为 600,则为 600-700px)。

因此,这里有函数

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

    // if the user hasn't scrolled far enough (>100px to the end)
    if (windowRelativeBottom > document.documentElement.clientHeight + 100) break;

    // let's add more data
    document.body.insertAdjacentHTML("beforeend", `<p>Date: ${new Date()}</p>`);
  }
}

在沙盒中打开解决方案。

重要性:5

创建一个“回到顶部”按钮,以帮助页面滚动。

它应该像这样工作

  • 当页面没有向下滚动至少一个窗口高度时,它是不可见的。
  • 当页面向下滚动超过窗口高度时,左上角会出现一个“向上”箭头。如果页面回滚,它将消失。
  • 当单击箭头时,页面将滚动到顶部。

就像这样(左上角,滚动以查看)

为任务打开沙箱。

重要性:4

假设我们有一个速度较慢的客户端,并且希望节省他们的移动流量。

为此,我们决定不立即显示图像,而是用占位符替换它们,如下所示

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

因此,最初所有图像都是 placeholder.svg。当页面滚动到用户可以看到图像的位置时,我们将 src 更改为 data-src 中的图像,从而加载图像。

下面是在 iframe 中的示例

滚动它以查看按需加载的图像。

要求

  • 当页面加载时,屏幕上的那些图像应立即加载,在任何滚动之前。
  • 某些图像可能是常规的,没有 data-src。代码不应该触及它们。
  • 加载图像后,在滚动进出时不再重新加载。

P.S. 如果可以,请制作一个更高级的解决方案,该解决方案将“预加载”当前位置下方/之后的图像。

P.P.S. 只处理垂直滚动,不处理水平滚动。

为任务打开沙箱。

onscroll 处理程序应检查哪些图像可见并显示它们。

我们还希望在页面加载时运行它,以立即检测可见图像并加载它们。

代码应在文档加载时执行,以便它能够访问其内容。

或将其放在 <body> 底部

// ...the page content is above...

function isVisible(elem) {

  let coords = elem.getBoundingClientRect();

  let windowHeight = document.documentElement.clientHeight;

  // top elem edge is visible?
  let topVisible = coords.top > 0 && coords.top < windowHeight;

  // bottom elem edge is visible?
  let bottomVisible = coords.bottom < windowHeight && coords.bottom > 0;

  return topVisible || bottomVisible;
}

showVisible() 函数使用由 isVisible() 实现的可见性检查来加载可见图像

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 的一个变体,该变体“预加载”当前文档滚动上方/下方 1 页范围内的图像。

在沙盒中打开解决方案。

教程地图

评论

在评论之前阅读此内容…
  • 如果您有改进建议 - 请 提交 GitHub 问题 或提交请求,而不是发表评论。
  • 如果您无法理解文章中的内容 - 请详细说明。
  • 要插入几行代码,请使用 <code> 标记,对于多行 - 将其包装在 <pre> 标记中,对于 10 行以上 - 使用沙箱 (plnkrjsbincodepen…)