回到课程

加载可视化图像

重要程度: 4

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

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

<img src="/?originalUrl=https%3A%2F%2Fzh.javascript.info%2F%26quot%3Bplaceholder.svg%26quot%3B%2520width%3D%26quot%3B128%26quot%3B%2520height%3D%26quot%3B128%26quot%3B%2520data-src%3D%26quot%3Breal.jpg%26quot%3B%26gt%3B%253C%2Fcode">

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

这是在 iframe 中的一个示例:

滚动它可以看到图像是“按需”加载的。

要求:

  • 加载页面时,屏幕上的那些图像应该在滚动之前立即加载。
  • 有些图像可能是常规图像,没有 data-src。代码不应该改动它们。
  • 一旦图像被加载,它就不应该在滚动进/出时被重新加载。

P.S. 如果你有能力,可以创建一个更高级的解决方案,以“预加载”当前位置下方/之后一页的图像。

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

打开一个任务沙箱。

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

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

该代码应该在文档加载完成时执行,以便可以访问文档内容。

或者将该代码放在 <body> 底部:

// ...页面内容在上面...

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() 函数使用通过 isVisible() 实现的可见性检查,来加载可见图像:

function showVisible() {
  for (let img of document.querySelectorAll('img')) {
    let realSrc="/?originalUrl=https%3A%2F%2Fzh.javascript.info%2Fimg.dataset.src%3B%2520%2520%2520%2520if%2520(!realSrc)%2520continue%3B%2520%2520%2520%2520if%2520(isVisible(img))%2520%257B%2520%2520%2520%2520%2520%2520img.src%2520%3D%2520realSrc%3B%2520%2520%2520%2520%2520%2520img.dataset.src%2520%3D"';
    }
  }
}

showVisible();
window.onscroll = showVisible;

P.S. 此解决方案还有一个 isVisible 的变体,可以“预加载”当前文档滚动上方/下方 1 页内的图像

使用沙箱打开解决方案。