博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
谈谈实现瀑布流布局的几种思路
阅读量:5363 次
发布时间:2019-06-15

本文共 2264 字,大约阅读时间需要 7 分钟。

最近遇到这么一个需求,需要在手机上做一个两列的瀑布流布局,后来就把这个问题研究了一下,做个记录。

一般来讲,这种布局可以分为两种情况:

  1. 图片的数量是一定的,不需要页面滚动到底部时,再动态加载图片,只需要将图片排成若干列

  2. 图片的数量的不定的,页面触底时,需要从远程加载图片。

前者使用css的方法即可解决,后者则需要js来帮忙。

css解法

一、CSS多列布局

当我们展示的图片数量一定时,可以优先采用css解法。其中一种方法是借助css的多栏布局:

.photos{    column-count: 3;  column-gap: 10px;}

得到的效果如下:

See the Pen by imgss

() on .

二、flex布局

flex布局同样可以做到这一点,诀窍在于将flex-direction设为column;但是相对于多列布局,需要根据瀑布流的列数,计算一个合适的容器高度,不然可能会导致多出一行。如果你在下面的demo 中,看到了4列,不要怀疑,就是我计算的容器高度不合适导致的。。。

See the Pen by imgss

() on .

js解法

当图片需要动态插入时,上面的两种方法就不合适了,因为他们本质上是将图片按照纵向进行排列的。图片动态插入时通常我们希望图片是按横向插入到容器中的。这时候就需要js来帮忙了。首先,我们看看瀑布流和背包问题的关系。

瀑布流的基本思路是将一堆图片放到若干列中,列与列之间的高度比较均匀,而不会相差太大。假如我们要分成两列,那么,问题就变成了,从 n 张图片中挑出 m 张,使这 m 张图片的总高度尽量接近 n 张图片总高度的 1 / 2。于是这就变成了一个

01背包问题

背包问题是啥这里不做展开,说白了是将一个复杂的问题分解为几个简单的问题,大佬们讲的都比我好,网上也有各个语言版本的实现,不太了解的同学可以查看上面的链接。这里直接放一个函数

function dp(ws, vs, limit) {    let len = ws.length;    let tables = new Array(len).fill().map(x => [])    tables[-1] = new Array(limit + 1).fill(0);    for(let i = 0; i < len; i++) {        for (let w = 0; w <= limit; w++) {            if (ws[i] > w) {                tables[i][w] = tables[i-1][w]            } else {                tables[i][w] = Math.max(tables[i-1][w], tables[i-1][w-ws[i]] + vs[i])            }        }    }    // 回溯得到应该选哪些    let max = limit;    let selected = [];    for (let idx = len - 1; idx >= 0; idx--) {        if (ws[idx] <= max) {            let isSelected = tables[idx-1][max] < tables[idx-1][max-ws[idx]] + vs[idx]            if(isSelected) {                selected.push(idx);                max = max - ws[idx];            }        }    }    return selected;}

有了这个解法之后,我们也就不难写出一个瀑布流布局。具体思路是:假设我们要做一个3列的瀑布流布局,那么可以不断从图片数组中选出一组图片,使图片的高度接近总高度的1/3,最终得到3组图片。下面是一个代码片段

// colCount 表示要生成几列      while(colCount--) {          // 获取被选出的照片索引          let idxs = dp(photoHeights, photoHeights, aver)          // 得到被选出的一组图片          let photoCol = photos.filter((p,idx) => idxs.includes(idx))           this.cols.push(photoCol)          photoHeights.forEach((v,i) => {          if (idxs.includes(i)) {            photoHeights[i] = null          }        })      }

下面这个demo就是按上面的思路实现的,可以拖动下面的滑块来改变列数,观察底部的间隙。在使用背包算法解决瀑布流问题时,一个需要我们注意的地方是,要将图片高度转化成整数。

See the Pen by imgss

() on .

参考文章:

转载于:https://www.cnblogs.com/imgss/p/11072266.html

你可能感兴趣的文章
软考知识点梳理--项目评估
查看>>
把特斯拉送上火星的程序员,马斯克!
查看>>
三测单
查看>>
MyBatis 缓存
查看>>
SQL中left outer join与inner join 混用时,SQL Server自动优化执行计划
查看>>
mac下python实现vmstat
查看>>
jxl.dll操作总结
查看>>
成员函数对象类的const和非const成员函数的重载
查看>>
机器学习实战-----八大分类器识别树叶带源码
查看>>
eclipse git 新的文件没有add index选项
查看>>
java 泛型
查看>>
VC NetShareAdd的用法
查看>>
java web项目中后台控制层对参数进行自定义验证 类 Pattern
查看>>
图论学习一之basic
查看>>
Java的Array和ArrayList
查看>>
记录Ubuntu 16.04 安装Docker CE
查看>>
安东尼奥·维瓦尔第——巴洛克音乐的奇葩
查看>>
pandas的增删改查
查看>>
HDU 5933/思维
查看>>
字节对齐
查看>>