• 手摸手,带你实现移动端H5瀑布流布局


    移动端瀑布流布局是一种比较流行的网页布局方式,视觉上来看就是一种像瀑布一样垂直落下的排版。每张图片并不是显示的正正方方的,而是有的长有的短,呈现出一种不规则的形状。但是它们的宽度通常都是相同的

    因为移动端瀑布流布局主要为竖向瀑布流,因此本文所探讨的是竖向瀑布流

    特点

    竖向瀑布流布局主要有下面几种特点:

    • 一般出现在移动端 H5 页面底部
    • 主要以图片或视频为主
    • 降低页面复杂度,节省空间,可以容纳更多内容
    • 不规则展示,不会那么枯燥,用户体验好
    • 难以或者说不能滚动到页面最底部

    不同于传统的分页,瀑布流因为以上这些特点一般被用在这些场景下:

    • 推荐机制下的信息 即根据用户画像推荐或者运营人员推荐的信息
    • 大分类下的信息流 展示的信息有很多,它们的大分类都是相同的,适合用户不明确详细需要获得什么信息或商品的情况下
    • 各个信息或商品之间没有比较强的相关性 和上面一条类似,展示的不是千遍一律的东西,相对独立的信息或商品也许能让用户意外发掘到想要的东西

    实现

    一般来说主要分为 CSS 实现和 JS 实现

    CSS 实现主要是用到一些专门的样式属性,实现起来简单,但是往往会有兼容性问题

    JS 实现的方法则不存在这些问题,并且能实现比较个性化的需求,但是实现起来比较麻烦

    column 多列布局方法

    column 实现瀑布流主要依赖两个属性

    column-count 属性是设置共有几列

    column-gap 属性是设置每列之间的间隔

    column 兼容性

    代码

    <style>
      .pic {
        column-count: 3;
        column-gap: 5px;
      }
    
      .pic .item {
        border: 1px solid #ccc;
        margin-bottom: 5px;
      }
    
      .item img {
        width: 100%;
      }
    </style>
    
    <body>
      <div class="pic">
        <div class="item">
          <!-- 获取 api 取到的图片地址 -->
          <img src="" />
          <div>001</div>
        </div>
        ······
        <div class="item">
          <img src="" />
          <div>008</div>
        </div>
      </div>
    </body>
    

    flex 弹性布局方法

    flex 实现瀑布流需要给父元素设置为横向排列。然后通过设置 flex-flow: column wrap 使其换⾏

    代码

    <style>
      .pic {
        display: flex;
        flex-flow: column wrap;
        height: 100vh;
      }
    
      .item {
        /* 每行展示 3 个 */
        width: calc(100%/3 - 5px);
        border: 1px solid #ccc;
        margin-bottom: 5px;
      }
    
      .item img {
        width: 100%;
      }
    </style>
    <body>
      <div class="pic">
        <div class="item">
          <!-- 获取 api 取到的图片地址 -->
          <img src="" />
          <div>001</div>
        </div>
        ······
        <div class="item">
          <img src="" />
          <div>008</div>
        </div>
      </div>
    </body>
    

    效果

    可以发现图片排序顺序是先垂直方向,然后才是水平方向的。column 多列布局和 flex 弹性布局方法实现的效果图最终相似

    JS + 懒加载方法

    在不考虑兼容性或者没有特殊图片展示顺序需求下,只是实现瀑布流的话上面两种方案是够用的。如果要实现一些个性化的需求的话,还是得用 JS

    主要思路就是:

    1. 先将第一行排满
    2. 计算第一行的所有图片高度,将第二行第一张图放在第一行最矮的图片后面
    3. 进行玩步骤 2,重新计算当前所有列高度,避免步骤 2 添加完成后,该列高度还是最矮

    完整代码

    <!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" />
        <title>JS实现瀑布流</title>
        <style>
            .item {
                box-sizing: border-box;
                border: 1px solid #ccc;
                position: absolute;
                /* 展示为三列,减去间隔宽度 */
                width: calc(100% / 3 - 5px);
            }
    
            .item img {
                width: 100%;
            }
        </style>
    </head>
    
    <body>
        <div id="pic">
            <div class="item">
                <img src="..." />
                <div>001</div>
            </div>
            <!-- 剩余图片,实际场景中应该使用for循环 -->
            <div class="item">
                <img src="..." />
                <div>015</div>
            </div>
        </div>
    </body>
    <script>
        var pic = document.getElementById('pic');
        var items = pic.children;
        // 相邻间距为5像素
        var space = 5;
        var picAmount = 15;
    
        window.onload = function () {
            function getClient() {
                return {
                    width: window.innerWidth ||
                        document.documentElement.clientWidth ||
                        document.body.clientWidth,
                    height: window.innerHeight ||
                        document.documentElement.clientHeight ||
                        document.body.clientHeight,
                };
            }
    
            function getScrollTop() {
                return document.documentElement.scrollTop ||
                    window.pageYOffset ||
                    document.body.scrollTop;
            }
    
            waterFall();
    
            function waterFall() {
                var pageWidth = getClient().width;
                var itemWidth = items[0].offsetWidth;
                var columns = parseInt(pageWidth / (itemWidth + space));
                var picList = [];
                for (var i = 0; i < items.length; i++) {
                    if (i < columns) {
                        items[i].style.top = 0;
                        items[i].style.left = (itemWidth + space) * i + 'px';
                        picList.push(items[i].offsetHeight);
                    } else {
                        // 找到数组中最小高度的那一列,并拿到其下标
                        var minHeight = picList[0];
                        var index = 0;
                        for (var j = 0; j < picList.length; j++) {
                            if (minHeight > picList[j]) {
                                minHeight = picList[j];
                                index = j;
                            }
                        }
                        items[i].style.top = picList[index] + space + 'px';
                        items[i].style.left = items[index].offsetLeft + 'px';
                        // 操作列的高度 = 当前列原本高度 + 图片的高度 + 相邻的间距
                        picList[index] = picList[index] + items[i].offsetHeight + space;
                    }
                }
            }
            window.onresize = function () {
                waterFall();
            };
    
            // 监听滚动事件,模拟懒加载
            window.onscroll = function () {
                // 如果滚动到的位置比当前显示的最后一个图片高,则请求新的图片
                if (
                    getClient().height + getScrollTop() >=
                    items[items.length - 1].offsetTop
                ) {
                    // 后续的新图片
                    var datas = [...];
                    for (var i = 0; i < datas.length; i++) {
                        picAmount += 1;
                        var div = document.createElement('div');
                        div.className = 'item';
                        div.innerHTML = `<img src="${datas[i]}" alt=""><div>0${picAmount}</div>`;
                        pic.appendChild(div);
                    }
                    waterFall();
                }
            };
        };
    </script>
    
    </html>
    

    效果

    不同于上面两个 css 实现的瀑布流,JS 实现的图片排序顺序是先水平方向,然后才是垂直方向

    可以看到当滚动页面的时候,新的图片会不断添加进来,这样就实现懒加载了

    总结

    如果实现效果简单不考虑兼容的的话可以选择使用 CSS 实现;若要兼容老版本浏览器或者实现一些个性化的需求还是得用 JS 实现

    当然除了上文说的这些方法以外,也可以使用第三方库 Masonry 实现

  • 相关阅读:
    Biotin-SS-NHS ester|生物素-二硫键-活性酯|CAS:122266-55-1具有良好的水溶性
    用栈实现队列、用队列实现栈(C语言_leetcode_232+225)
    Ubuntu 设置只允许国内的 IP 访问
    C/C++内存管理
    DNS查询流程
    Python数据攻略-Pandas与机器学习数据准备
    《公共管理学》重点总结-陈振明版
    ISP技术概述
    openssl漏洞检查修复
    ROS action客户端和服务端通信(Ubuntu )
  • 原文地址:https://www.cnblogs.com/rainy-night/p/16242712.html