likes
comments
collection
share

阿里面试题:瀑布流布局(手撕版)前言 朋友们要问了,什么是瀑布流布局。瀑布流布局就是多行等宽元素排列,但是等宽不等高,后

作者站长头像
站长
· 阅读数 16

前言

朋友们要问了,什么是瀑布流布局。瀑布流布局就是多行等宽元素排列,但是等宽不等高,后边的元素以此排列添加到前一行最矮元素的下方。简单说它能够在同样的空间中展示出更多的内容,吸引用户继续向下滑动浏览,并提供更好的用户体验,如下方小红书布局。

阿里面试题:瀑布流布局(手撕版)前言 朋友们要问了,什么是瀑布流布局。瀑布流布局就是多行等宽元素排列,但是等宽不等高,后

如何实现

  • 这里我准备了20张图片
  • 框架搭建:id为container的div内有20个类名为box的div,盒子中放类名为box-img的盒子用于放img标签
<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>

由于div为块级元素,目前状态应该是一行一张的图片,接下来我们编写一下css部分的代码

  • 首先通配符将所有元素的内外边距取消
  • container容器设置相对定位,后续他的子容器需要相对于他来做定位
  • box做浮动,从左向右排列
  • 每个box-img设置好宽度,不要宽高同时设置,避免图片变形
  • img继承父级元素(box-img)的宽度就行
<style>
        * {
            margin: 0;
            padding: 0;
        }

        #container {
            position: relative;

        }

        .box {
            float: left;
            padding: 5px;
        }

        .box-img {
            width: 150px;
            padding: 5px;
            border: 1px solid #09f758;
        }

        img {
            width: 100%;
        }
    </style>

目前状态:

阿里面试题:瀑布流布局(手撕版)前言 朋友们要问了,什么是瀑布流布局。瀑布流布局就是多行等宽元素排列,但是等宽不等高,后 瀑布流布局需要把下一个照片放在上一行最矮的图片下面,因此接下来我们缕一缕思路编写js代码 - 首先要获取屏幕的宽度,因为它决定了一行能放多少张图片documemt.documentElement.childWidth

  • 我们可以写一个函数,将父级容器传进来,通过父级容器获取到有多少个box即多少张图片
  • 要知道一行能放多少张图片,因此我们还需要获取到每一张照片的宽度。offsetWidth
  • 得到了屏幕宽度和照片宽度后,通过除法可以得到一个小数,我们需要做向下取整。如可以放3.5张照片我们就放3张
  • 开始没有设置容器的宽度,得到了照片宽度和一行能放多少张之后,我们可以设置容器宽度
  • 接下来就是瀑布流的重点操作了,如何把下一张照片放到上一行中最矮的那一列下面?
  • 思路:我们可以定义一个数组,遍历一遍第一行的照片,获取到每一张照片的高度,并存储到数组中,然后获取到一行中最矮的那一列(Math.min.apply),并通过indexOf获取到是哪一列(下标),还记得我们最开始设置容器的定位为相对定位吗?这里就有作用了,接下来摆放下一张图片的位置,首先将图片的定位模式改为绝对定位,然后设置这张图片的高度(距离顶部的位置):高度即最矮的那一列的下面ccontent[i].style.top = minHeight + 'px';设置距离左边的位置:ccontent[i].style.left = ccontent[minIndex].offsetLeft + 'px';,最后还需要更新一下这一列的高度BoxHeightArr[minIndex] += ccontent[i].offsetHeight;
// 获取到用户屏幕的宽度,决定了一行能放下几张图片
// 操作下一张图,放到上一行最矮的列下面

function imgLocation(parent, content) {
    var cparent = document.getElementById(parent);

    // 有多少张图片
    // var ccontent = document.querySelectorAll('.box');
    // var ccontent = document.querySelectorAll('#container .box');
    var ccontent = getChildElement(cparent, content);
    // console.log(ccontent.length);

    // 获取每一个box的宽度
    var imgWidth = ccontent[0].offsetWidth;

    // 屏幕一行能放下几个图片  5.6 取整放5张
    var num = Math.floor(document.documentElement.clientWidth / imgWidth);

    //设置container的宽度
    cparent.style.width = `%{imgWidth *num}px`;

    // 要操作的是哪一张?num+1,取到每一列的高度
    var BoxHeightArr = [];
    for (let 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] += ccontent[i].offsetHeight;

            console.log(minIndex);
        }
    }

    // console.log(BoxHeightArr);

}

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

}

imgLocation('container', 'box');

效果

阿里面试题:瀑布流布局(手撕版)前言 朋友们要问了,什么是瀑布流布局。瀑布流布局就是多行等宽元素排列,但是等宽不等高,后

至此瀑布流就已经实现了,但是在我们编写代码时有什么需要注意的呢?

  • 小白朋友在敲代码的时候可以为了学习而学习,例如:我们知道要获取里面有多少张图片可以直接通过内置方法var ccontent = document.querySelectorAll('.box');但是为什么不直接使用呢?因为代码不够优雅,后续如果页面再出现类名为box的标签,那整个代码都需要修改了。或者使用var ccontent = document.querySelectorAll('#container .box');为什么也不用呢?因为为了学习编写代码的能力学习封装思想。我们可以自己定义一个方法来获取图片的数量。var ccontent = getChildElement(cparent, content);怎么实现的呢?定义一个数组用于存放照片,后续获取数组长度就知道有多少张照片了,通过getElementsByTagName('*')方法得到容器中所有的标签,但是我们知道照片只存放在box的box-img的img标签中,因此倘若我们有20张照片,这里获取到的数量便是60个,因此我们可以遍历一下,通过className属性获取到类名为box的标签,最后通过数组push方法存入数组,并将数组返回。
function getChildElement(parent, child) {
    // 获取parent中所有的child
    var childArr = [];
    // 返回的是数组结构
    var allChild = parent.getElementsByTagName('*');
    // 跳出所有Child中的box
    for (let i = 0; i < allChild.length; i++) {
        if (allChild[i].className == child) {
            childArr.push(allChild[i]);
        }
    }
    return childArr;

}

那么,假如有一天你去到阿里面试,面试官问你瀑布流是如何实现的,看完本篇后,你能够游刃有余的给面试官解答吗?

转载自:https://juejin.cn/post/7361234872779669516
评论
请登录