阿里面试题——如何实现瀑布流

624 阅读6分钟

前言

当你想要为你的网站或应用增添一抹现代化的魅力时,瀑布流布局是一个不可忽视的选择。随着网络内容的不断增长和多样化,传统的网格布局已经不能完全满足用户的需求。这时候,JavaScript 的瀑布流布局应运而生,为我们提供了一种动态、灵活且吸引人的方式来展示内容。在这篇文章中,我们将深入探讨如何利用 JavaScript 来实现瀑布流布局,以及它如何为我们的项目带来新的可能性。

正文

首先我们了解一下什么是瀑布流?

瀑布流是一种在网页设计和应用中常见的布局方式,也称为瀑布式布局。它的特点是将内容以类似瀑布流水般的方式一列一列地排列展示,每一列的宽度固定,而高度则根据内容的长度自适应。通常情况下,内容项按照顺序从上到下依次排列,当一列的内容填满时,会自动开始下一列的排列,而不是等待整个行或整个页面都填满后再排列下一行。

image.pngimage.png

  • 这两张就是瀑布流的展示,那么瀑布流布局通常在什么场景实现呢?它又有什么优势呢?

瀑布流布局常用于展示图片、新闻、产品等具有不同高度的内容。它能够灵活地适应不同尺寸和分辨率的屏幕,提供更好的用户体验。瀑布流布局也常见于社交媒体网站、电子商务网站和图片分享平台等地方,因为它可以有效地利用空间,同时展示大量的内容。

现在开始我们来展示并分析一下瀑布流的代码

HTML部分

    <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>瀑布流布局</title>
    
</head>
<body>
    <div id="container">
        <div class="box">
            <div class="box-img">
                <img src="./img/1.webp" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/2.webp" alt="">
            </div>
        </div> 
        <div class="box">
            <div class="box-img">
                <img src="./img/3.webp" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/4.webp" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/5.webp" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/6.webp" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/7.webp" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/8.webp" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/9.webp" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/10.webp" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/1.webp" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/2.webp" alt="">
            </div>
        </div> 
        <div class="box">
            <div class="box-img">
                <img src="./img/3.webp" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/4.webp" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/5.webp" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/6.webp" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/7.webp" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/8.webp" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/9.webp" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box-img">
                <img src="./img/10.webp" alt="">
            </div>
        </div>
    </div>

    <script src="./index.js"></script>
</body>
</html>

  1. <body>:文档的主体部分,包含了页面的实际内容。

    • <div id="container">:一个包含所有盒子的容器。

      • .box:每个盒子,包含了一个具有类名为.box-img的子元素,用于展示图片。

        • .box-img:每个盒子中图片的容器,包含了一个<img>元素,用于展示图片。
  2. 每个图片都被包裹在一个<div class="box-img">中,然后被放置在一个.box中,这样的结构使得每张图片都具备了瀑布流的特性,即不规则的排列方式。

这段代码中的图片路径指向了当前目录下的img文件夹中的图片,图片文件名从1.webp到10.webp,因此,预期在页面上会展示出10张webp格式的图片。

在写完html部分后我们还需要增添部分css样式

    <style>
        * {
            margin: 0;
            padding: 0;
        }
        #container {
            position: relative;
        }
        .box {
            float: left;
            padding: 3px;
        }
        .box-img {
            width: 150px;
            padding: 5px;
            bottom: 1px solid green;
        }
        img {
            width: 100%;
        }
    </style>
  1. * { margin: 0; padding: 0; }: 这段 CSS 代码将所有元素的内边距和外边距设置为零。* 是通配符选择器,匹配所有元素。
  2. #container { position: relative; }: 这是一个 ID 选择器,用于选择具有 id 属性为 "container" 的元素。它将该元素的定位属性设置为相对定位。这意味着它在文档流中仍占据其原始位置,但可以通过 toprightbottomleft 属性进行微调。
  3. .box { float: left; padding: 3px; }: 这是一个类选择器,用于选择所有具有类名为 "box" 的元素。它将这些元素设置为浮动到其父元素的左侧,并给它们添加了3像素的内边距。
  4. .box-img { width: 150px; padding: 5px; bottom: 1px solid green; }: 这也是一个类选择器,用于选择所有具有类名为 "box-img" 的元素。它将这些元素的宽度设置为150像素,并添加了5像素的内边距。但是,bottom: 1px solid green; 这一行代码有错误。它应该是 border-bottom: 1px solid green; 才能给元素的底部添加1像素的绿色边框。
  5. img { width: 100%; }: 这是一个标签选择器,用于选择所有 <img> 元素,并将它们的宽度设置为其父元素的100%,这样图片就会根据其父元素的宽度进行缩放。

需要注意的是,代码中有一个小错误,bottom: 1px solid green; 应该修改为 border-bottom: 1px solid green; 才能达到预期的效果。我们设置合理的宽度可以更好的展示出瀑布流的效果

最后,到了js部分的编写,我们要实现一个图片布局的功能,主要用于将一组图片按照一定规则布局在页面上



imgLocation('container', 'box')

function imgLocation(parent, content) {
    // 有多少张图
    var cparent = document.getElementById(parent)
    var ccontent = getChildElement(cparent, content)   // document.querySelectorAll('#container .box')
    // 每一个box的宽度
    var imgWidth = ccontent[0].offsetWidth
    var num = Math.floor(document.documentElement.clientWidth / imgWidth)
    cparent.style.width = `${imgWidth * num}px`
  
    // 要操作的是哪一张,每一列的高度
    var BoxHeightArr = []
    for (var i = 0; i < ccontent.length; i++) {
      if (i < num) { // 第一行
        BoxHeightArr[i] = ccontent[i].offsetHeight
      } else { // 要操作的
        var minHeight = Math.min.apply(null, BoxHeightArr)
        var minIndex = BoxHeightArr.indexOf(minHeight)
  
        // 摆放图片的位置
        ccontent[i].style.position = "absolute"
        ccontent[i].style.top = minHeight + "px"
        ccontent[i].style.left = ccontent[minIndex].offsetLeft + "px"
  
        // 更新这一列的高度
        BoxHeightArr[minIndex] = BoxHeightArr[minIndex] + ccontent[i].offsetHeight
      }
    }
  
  
    console.log(BoxHeightArr);
    
  }

function getChildElement(parent, child) {
    //获取parent中所有的child
    var childArr = [];
    var allChild = parent.getElementsByTagName('*');
    //挑出所有的box
    for (let i = 0; i< allChild.length; i++) {
        if (allChild[i].className == child) {
            childArr.push(allChild[i]);
        }
    }
    return childArr;
}


1. imgLocation 函数:这是主要的布局函数,接受两个参数,parent 表示父容器的 id,content 表示子元素的类名。

1. getChildElement 函数:用于获取父元素中指定类名的所有子元素。

1. 在 imgLocation 函数中,首先获取了父容器以及所有的子元素,并计算了每个图片的宽度 imgWidth,然后根据页面宽度和图片宽度计算出一行能容纳多少张图片 num,并设置了父容器的宽度为 imgWidth * num

1. 接下来是对每张图片的布局操作。通过遍历所有子元素,对于第一行的图片,将其高度记录在 BoxHeightArr 数组中,对于后续的图片,找到 BoxHeightArr 中最小高度的列,将当前图片定位到该列下,并更新该列的高度。

1. 最后打印输出 BoxHeightArr 数组,这个数组记录了每一列的高度。

这段代码的主要思路是利用绝对定位,将图片按照每列高度最小的方式依次排列。

总结

在这篇文章中,我们深入探讨了瀑布流布局的实现原理及其在网页设计中的应用。通过代码实现瀑布流,我们不仅能够打造出更具吸引力和交互性的网页,还能提升用户的浏览体验,让他们更轻松地发现并享受到所需内容。

瀑布流布局的灵活性和适应性使其成为现代网页设计的重要工具之一。我们可以通过不断优化布局算法、提高页面加载速度以及保证响应式设计的实现,进一步提升瀑布流在不同设备上的表现效果。

正如技术的不断发展与创新,瀑布流布局也将不断演进,并在各行业的网页设计中发挥更重要的作用。希望本文能够为您带来一些启发和指导,激发您对于瀑布流布局的兴趣,让您在未来的项目中能够运用这一强大的布局技术,创造出更加引人入胜的网页作品。