面试官:请简单的实现瀑布流

334 阅读6分钟

前言:

当面试官询问如何实现瀑布流时,这通常涉及到前端开发中的一个重要概念。瀑布流(Waterfall Flow)是一种页面布局方式,通过动态加载内容使页面呈现类似瀑布般的效果,这种布局通常用于展示图片或卡片式内容,可以有效利用页面空间。而我想增加懒加载(Lazy Loading)则是一种优化手段,它延迟加载页面上不是立即可见的内容,只有当用户滚动页面或进行特定交互时才加载这些内容,以提升页面加载速度和用户体验。

瀑布流

  • 瀑布流(Waterfall Flow)是一种网页布局方式,通常用于展示图片或卡片式内容。它的特点是将内容块按照一定的规则排列,使得整体布局类似于瀑布般的效果,每一列的内容高度可以不同,但整体保持对齐。

  • 瀑布流布局最常见于图片墙、社交媒体动态流和商品展示等页面。它能够有效地利用页面空间,使得页面看起来更加动态和生动。通过瀑布流布局,用户可以一次性浏览多个内容块,而不必像传统的网格布局那样严格对齐每个内容的顶部和底部。

  • 而实现瀑布流布局通常需要结合HTML、CSS和JavaScript来动态调整每个元素的位置和大小。CSS可以用于定义每个列的宽度和样式,而JavaScript则负责计算和调整每个内容块的位置,以响应页面尺寸的变化或者动态加载新内容。

  1. 布局特点:瀑布流布局以其不规则的列排列方式著称,每一列的高度可以不同,但各列内容整体保持对齐,使得页面呈现出类似瀑布落差的视觉效果。
  2. 应用场景:常用于展示图片、卡片式内容或动态生成的内容,如社交媒体动态流、商品列表等,能够有效利用页面空间,使得页面看起来更加动态和吸引人。

懒加载:

  • 懒加载(Lazy Loading)是一种优化网页性能的技术手段,其核心思想是延迟加载页面上的资源或内容,只有在需要时才加载。这种方式与传统的一次性加载所有资源的方式相比,能够显著减少页面的加载时间和带宽消耗,从而提升用户的整体体验。

  • 具体来说,懒加载主要应用于图片、视频和其他大型媒体文件的加载,以及页面中的某些动态生成的内容。常见的实现方式包括:

  1. 图片懒加载:在页面加载时,只加载可视区域内的图片,当用户滚动页面到达某张图片附近时,再加载该图片。这可以通过监听滚动事件,检测图片位置与可视区域的关系来实现。
  2. 无限滚动加载:在网页中,当用户滚动到页面底部时,通过异步加载更多内容,如新的列表项、文章或商品。这种技术通常与瀑布流布局结合使用,使得用户可以无缝地浏览更多内容而无需手动加载新页面或点击“加载更多”按钮。
  3. 延迟加载其他资源:除了媒体文件,懒加载还可以应用于页面的其他资源,例如JavaScript文件、CSS样式或特定模块的HTML内容。这些资源可以根据用户交互或特定事件进行延迟加载,以提高页面的响应速度和初次加载的效率。

具体实例:

(一).html结构

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="./1.css">
  <title>Document</title>
  <script src="./1.js"></script>
</head>

<body>
  <!-- 图片容器 -->
  <div class="image-container">
    <!-- 图片 -->
    <img src="01.jpg" data-src="01.jpg" alt="Image 1" class="lazy-image grid-image">
    <figcaption class="image-caption"> 图片 1 </figcaption>
    <img src="02.jpg" data-src="02.jpg" alt="Image 2" class="lazy-image grid-image">
    <figcaption class="image-caption"> 图片 2 </figcaption>
    <img src="03.jpg" data-src="03.jpg" alt="Image 3" class="lazy-image grid-image">
    <figcaption class="image-caption">图片 3 </figcaption>
    <img src="04.jpg" data-src="04.jpg" alt="Image 4" class="lazy-image grid-image">
    <figcaption class="image-caption">图片 4</figcaption>
    <img src="05.jpg" data-src="05.jpg" alt="Image 5" class="lazy-image grid-image">
    <figcaption class="image-caption">图片 5 </figcaption>
    <img src="06.jpg" data-src="06.jpg" alt="Image 6" class="lazy-image grid-image">
    <figcaption class="image-caption">图片 6 </figcaption>
    <img src="07.jpg" data-src="07.jpg" alt="Image 7" class="lazy-image grid-image">
    <figcaption class="image-caption">图片 7 </figcaption>
    <img src="08.jpg" data-src="08.jpg" alt="Image 8" class="lazy-image grid-image">
    <figcaption class="image-caption">图片 8 </figcaption>
    <img src="09.jpg" data-src="09.jpg" alt="Image 9" class="lazy-image grid-image">
    <figcaption class="image-caption">图片 9 </figcaption>
    <img src="10.jpg" data-src="10.jpg" alt="Image 10" class="lazy-image grid-image">
    <figcaption class="image-caption">图片 10 </figcaption>
    <img src="11.jpg" data-src="11.jpg" alt="Image 11" class="lazy-image grid-image">
    <figcaption class="image-caption">图片 11 </figcaption>
    <img src="12.jpg" data-src="12.jpg" alt="Image 12" class="lazy-image grid-image">
    <figcaption class="image-caption">图片 12 </figcaption>
    <img src="13.jpg" data-src="13.jpg" alt="Image 13" class="lazy-image grid-image">
    <figcaption class="image-caption">图片 13 </figcaption>
    <img src="14.jpg" data-src="14.jpg" alt="Image 14" class="lazy-image grid-image">
    <figcaption class="image-caption">图片 14 </figcaption>
    <img src="15.jpg" data-src="15.jpg" alt="Image 15" class="lazy-image grid-image">
    <figcaption class="image-caption">图片 15 </figcaption>
    <img src="16.jpg" data-src="16.jpg" alt="Image 16" class="lazy-image grid-image">
    <figcaption class="image-caption">图片 16 </figcaption>
    <img src="17.jpg" data-src="17.jpg" alt="Image 17" class="lazy-image grid-image">
    <figcaption class="image-caption">图片 17 </figcaption>
    <img src="18.jpg" data-src="18.jpg" alt="Image 18" class="lazy-image grid-image">
    <figcaption class="image-caption">图片 18 </figcaption>
    <img src="19.jpg" data-src="19.jpg" alt="Image 19" class="lazy-image grid-image">
    <figcaption class="image-caption">图片 19 </figcaption>
    <img src="20.jpg" data-src="20.jpg" alt="Image 20" class="lazy-image grid-image">
    <figcaption class="image-caption">图片 20 </figcaption>
    <img src="21.jpg" data-src="21.jpg" alt="Image 21" class="lazy-image grid-image">
    <figcaption class="image-caption">图片 21 </figcaption>




  </div>

  <!-- 加载完成提示信息 -->
  <div class="loading-message" id="loadingMessage">
  </div>

(二).瀑布流css样式


.image-container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  grid-gap: 10px;
}

.lazy-image {
  width: 100%;
  height: auto;
  display: block;
  transition: opacity 0.3s ease-in-out;
 
}


.image-caption {
  text-align: center;
  margin-top: 5px;
}

.loading-message {
  display: none;
  text-align: center;
  margin-top: 20px;
  font-size: 18px;
}

(三).懒加载js


// 使用缓存来存储已加载的图片
const imageCache = {};

// 当页面加载完成后执行
window.addEventListener('DOMContentLoaded', () => {
  loadLazyImages();
});

// 加载所有的图片
function loadLazyImages() {
  const images = document.querySelectorAll('.lazy-image');
  const totalImages = images.length;
  let loadedImages = 0;

  images.forEach(image => {
    const src = image.dataset.src;

    // 如果图片已经加载过,直接从缓存中获取
    if (imageCache[src]) {
      image.src = imageCache[src];
      loadedImages++;
      checkAllImagesLoaded(totalImages, loadedImages);
      return;
    }

    const observer = new IntersectionObserver(entries => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const img = entry.target;
          img.src = img.dataset.src;
          observer.unobserve(img);
          img.addEventListener('load', () => {
            console.log('Image loaded: ', img.src);
            // 将加载过的图片存入缓存
            imageCache[src] = img.src;
            loadedImages++;
            checkAllImagesLoaded(totalImages, loadedImages);
          });
        }
      });
    }, {
      root: null,
      threshold: 0
    });

    observer.observe(image);
  });
}

// 检查所有图片是否已加载完成
function checkAllImagesLoaded(total, loaded) {
  if (total === loaded) {
    // 在控制台输出提示信息
    console.log('所有图片已经加载完毕。');
    // 显示加载完成提示
    document.getElementById('loadingMessage').style.display = 'block';
  }
}

(四).实现效果:

image.png

image.png

image.png

总的来说:

当瀑布流布局和懒加载技术结合使用时:

  1. 提升用户体验

    • 流畅的加载体验:通过懒加载技术,只有当用户滚动页面到特定区域时才加载内容,避免了一次性加载大量资源导致的页面延迟和卡顿现象。
    • 动态视觉效果:瀑布流布局展示出内容块不规则的瀑布落差,结合懒加载,用户在滚动页面时可以逐步看到新的内容块动态加载,增强了页面的视觉吸引力和动态感。
  2. 优化页面性能

    • 减少初始加载时间:通过懒加载,页面初始加载时只加载可视区域内的内容,减少了不必要的网络请求和资源加载时间,提升了页面的初始加载速度。
    • 减少带宽消耗:只加载用户可见区域的内容,有效减少了带宽的消耗,特别是在移动设备和网络条件较差的情况下尤为显著。
  3. 技术实现要点

    • JavaScript控制:使用JavaScript编写懒加载和瀑布流布局的逻辑,监听滚动事件或用户交互,动态计算和调整内容块的加载时机和位置。
    • 性能平衡:优化懒加载的触发时机和加载策略,确保在提升用户体验的同时,不影响页面的整体性能和响应速度。
  4. 适用场景和应用

    • 图片墙和动态内容:适用于展示大量图片或动态生成的内容,如社交媒体的动态流、电商平台的商品展示页面等,能够有效地吸引用户的注意力和提升用户的浏览体验。
    • 移动端优化:对于移动设备来说,带宽和性能的限制更为明显,结合懒加载和瀑布流布局尤为重要,能够有效减少资源消耗和提升页面加载速度。