博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
图片横向等高瀑布流,每行占满,限制行数 的实现
阅读量:6370 次
发布时间:2019-06-23

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

图片的横向瀑布流,其实简单地按顺序排列就可以了

但要实现每行中各图片都等高(各行不一定等高,但每行里面等高),且每行都占满,就需要用到flex的特性了

控制每行图片高度都一致,可能会影响图片的比例,所以不能简单暴力地设置高度,需要按比例来动态计算

另外,如要限制图片展示的行数,则只需判断好每行总高度与容器总高度的关系即可

这里就来实现一下这个小功能

 

 

因为都是假数据的关系,图片的宽高值是随机数,并非原图宽高值,仅作参考

看完上面那张大大的图,先想一下可以怎么实现..

 

 

要实现每行都能够占满,需要用到 flex-grow 这个属性

flex-grow基于flex-basis基准值来计算,而flex-basis则基于项目的width、min|max-width相关的值来计算,或者手动定义

使用flex-grow可以分配按比例分配主轴的剩余空间

如果有10张图片需要放置,第一行仅可以放置四张图片,剩余100px的空间,那么各图片的flex-grow可以直接配置成图片的宽度width值,即可很方便精准地分配好这剩余的空间

第二行可以放五张图片,剩余N px的空间... 按照这种计算方式来铺满每一行

获取最近更新

上面页面模板中,flex-grow 与 width的值一致,用以按比例分配每行剩余空间

另外可以看到这里有个 padding-top 的百分比值

我们都知道  padding-top 的百分比值是基于父元素的宽度来计算的,根据盒模型,一般这种计算方式是为了获取固定宽高比

当父元素有宽度,但高度为0时,整体高度则由padding-top值来撑开,则父元素就有了一个设定的宽高比,

同时我们将子元素(这里是图片)position值设置为absolute,宽高占满父元素,则子元素图片也有了一定的宽高比,实现按比例的图片缩放

 

来看看对应的样式设置

body {
background-color: #f2f2f2;}.get-latest-update {
font-size: 20px; cursor: pointer; > a { color: #0183fd; text-decoration: none; }}.img-items {
display: flex; flex-wrap: wrap; overflow: hidden;}.img-item {
margin-right: 10px; margin-bottom: 10px; background-color: #fff; box-shadow: 0 0 10px #ddd; > a { position: relative; display: block; width: 100%; } img {
position: absolute; top: 0; left: 0; width: 100%; height: 100%; }}

 

那么,这个width和padding-top的该怎么计算出来呢

核心代码是

// 图片预定义的高度    var baseHeight = 200;        for (var i = 1; i <= num; ++i) {        var w = getRandom(width.min, width.max);        var h = getRandom(height.min, height.max);                imgs.push({            id: i,            src: imgSrcBase[Math.floor(i / 10)] + (i % 10 + 1) + '.jpg',            // 设置图片的宽度,需根据预定义的高度值来做好比例处理            // 为了让每行各图片按自身宽度自动flex-glow,同时利用这个比例处理保证每行图片的高度一致            width: w * baseHeight / h,                    height: h,            // padding-top的百分比,用以基于父元素宽度设置该元素的高度            // 为了保证图片宽高按比例            paddingTop: h / w * 100        });    }

paddingTop的值,按照以下这个映射关系来看就好

容器高度 == 容器宽度 * paddingTop %

最终会形成

容器高度 == 图片高度

容器宽度 == 图片宽度

所以 

图片高度 == 图片宽度 * paddingTop %

 

width值的计算可能比较绕

假设这里 width直接取 图片宽度w值,就会出现一行中图片高度不一致的情况

因为最终的图片高度即为容器的高度,而容器的高度是由容器宽度决定的(注意这里的paddingTop值已经确定),而容器宽度就是由这里的width来决定的。图片宽度的不同,就直接导致了最终高度的不同

所以,为了确保图片高度一致,假设有三张图片 50*50  100*100  50*150  放在了同一行中,flex布局会将三张图片所在容器的高度自适应为最高的那个150,如果flex-grow值起作用了,这个最高值还会再多一些

我们可以考虑最简单的情况,正好放满一行。那么最终三张图片的高度都应该为150,按照各自的图片比例来调整,则最终第一张图片宽度的计算  50 / 50 === width / 150 , 则 width = 50 / 50 * 150

可能有些行最高的图片还是不够高,为了也能够显示出比较大的图片,我们还可以定义好这个基准高度值,比如 baseHeight设置为 200

所以,最终每一张图片的宽度width值为 w / h * baseHeight

 

 

 还要一个问题,如何实现只显示三行

显示三行,每行的图片数量不固定,这是通过flex布局自动排列每一行的,都会经过 基本排列 -> 分配剩余空间 的步骤

目前想到的方法是对每一行的容器所占位置进行累加,最后对比即可

不过这种方式会有比较大的性能损耗,看还能不能有更优雅的做法吧

// 设置显示的图片行数function setLineLimit(num) {    // 内容区宽度    var contentWidth = $('.img-items').outerWidth();    // 定义的外边距    var marginWidth = 10;    // 每行宽度    var curWidth = 0;    // 行标识    var lineIndex = 1;        // 初始需将图片设置为可见,否则flex无法自适应排版    $('.img-item').show()        .each(function() {            var $item = $(this);            var itemWidth = $item.outerWidth();                        // 隐藏多余的行            if (lineIndex > num) {                $item.hide();                return;            }                        $item.show();                        // 某一行            if (curWidth + itemWidth + marginWidth <= contentWidth + marginWidth) {                curWidth += itemWidth + marginWidth;            }            // 下一行            else {                ++lineIndex;                curWidth = itemWidth;                                if (lineIndex > num) {                    $item.hide();                }            }        });}

主要注意的点是,为了兼顾视窗缩放的过程中,自动排列也能照常进行,在计算的时候需要将每个项先显示出来,再进入计算环节

// 视窗缩放时处理可视的图片$(window).resize(throttle(setLineLimit.bind(this, 3), 200));

 

完整JS代码

1 // 事件绑定  2 function addEvent(elem, type, handler) {  3     elem.addEventListener(type, handler, false);  4 }  5   6 function qs(selector) {  7     return document.querySelector(selector);  8 }  9  10 function qsa(selectors) { 11     return document.querySelectorAll(selectors); 12 } 13  14 // 函数节流,频繁操作中间隔 delay 的时间才处理一次 15 function throttle(fn, delay) { 16     delay = delay || 200; 17  18     var timer = null; 19     // 每次滚动初始的标识 20     var timestamp = 0; 21  22     return function () { 23         var arg = arguments; 24         var now = Date.now(); 25  26         // 设置开始时间 27         if (timestamp === 0) { 28             timestamp = now; 29         } 30  31         clearTimeout(timer); 32         timer = null; 33  34         // 已经到了delay的一段时间,进行处理 35         if (now - timestamp >= delay) { 36             fn.apply(this, arg); 37             timestamp = now; 38         } 39         // 添加定时器,确保最后一次的操作也能处理 40         else { 41             timer = setTimeout(function () { 42                 fn.apply(this, arg); 43                 // 恢复标识 44                 timestamp = 0; 45             }, delay); 46         } 47     } 48 } 49  50 // 获取随机数 51 function getRandom(min, max) { 52     return Math.round(Math.random() * (max - min + 1) + min); 53 } 54  55 // 构造图片数据 56 function createMockImgs(num) { 57     var imgs = []; 58      59     // 图片宽高数据范围 60     var width = { 61         min: 50, 62         max: 200 63     }; 64      65     var height = { 66         min: 150, 67         max: 300 68     }; 69      70     // 图片源 71     var imgSrcBase = [ 72         'http://www.deskcar.com/desktop/movietv/2009/2009227225145/', 73         'http://www.deskcar.com/desktop/fengjing/2017418153624/', 74         'http://www.deskcar.com/desktop/fengjing/2017418153624/', 75         'http://www.deskcar.com/desktop/fengjing/2017418153624/', 76         'http://www.deskcar.com/desktop/fengjing/2017418153624/', 77         'http://www.deskcar.com/desktop/else/20161228125639/', 78         'http://www.deskcar.com/desktop/fengjing/2017418153446/' 79     ]; 80      81     // 图片预定义的高度 82     var baseHeight = 200; 83      84     for (var i = 1; i <= num; ++i) { 85         var w = getRandom(width.min, width.max); 86         var h = getRandom(height.min, height.max); 87          88         imgs.push({ 89             id: i, 90             src: imgSrcBase[Math.floor(i / 10)] + (i % 10 + 1) + '.jpg', 91             // 设置图片的宽度,需根据预定义的高度值来做好比例处理 92             // 为了让每行各图片按自身宽度自动flex-glow,同时利用这个比例处理保证每行图片的高度一致 93             width: w * baseHeight / h,         94             height: h, 95             // padding-top的百分比,用以基于父元素宽度设置该元素的高度 96             // 为了保证图片宽高按比例 97             paddingTop: h / w * 100 98         }); 99     }100     101     return imgs;102 }103 104 // 视窗缩放时处理可视的图片105 $(window).resize(throttle(setLineLimit.bind(this, 3), 200));106 107 // 设置显示的图片行数108 function setLineLimit(num) {109     // 内容区宽度110     var contentWidth = $('.img-items').outerWidth();111     // 定义的外边距112     var marginWidth = 10;113     // 每行宽度114     var curWidth = 0;115     // 行标识116     var lineIndex = 1;117     118     // 初始需将图片设置为可见,否则flex无法自适应排版119     $('.img-item').show()120         .each(function() {121             var $item = $(this);122             var itemWidth = $item.outerWidth();123             124             // 隐藏多余的行125             if (lineIndex > num) {126                 $item.hide();127                 return;128             }129             130             $item.show();131             132             // 某一行133             if (curWidth + itemWidth + marginWidth <= contentWidth + marginWidth) {134                 curWidth += itemWidth + marginWidth;135             }136             // 下一行137             else {138                 ++lineIndex;139                 curWidth = itemWidth;140                 141                 if (lineIndex > num) {142                     $item.hide();143                 }144             }145         });146 }147 148 var mockImgs = createMockImgs(60);149 150 console.log(mockImgs);151 152 // 点击渲染153 addEvent(qs('.get-latest-update'), 'click', function() {154     renderList(mockImgs);155     setLineLimit(3);156 });157 158 var itemTpl = qs('#img-item-tpl').innerHTML;159 var itemsDOM = qs('.img-items');160 161 /**162 * 渲染数据163 * @param  {[type]} data [description]164 * @return {[type]}      [description]165  */166 function renderList(data) {167     var html = '';168     var fragment = document.createDocumentFragment();169 170     data.forEach(function(item) {171         var divTemp = document.createElement('div');172 173         // 模板替换174         divTemp.innerHTML = itemTpl.replace(/{
{(\w+)}}/g, function(input, match) {175 return match ? item[match] || '' : '';176 });177 178 fragment.appendChild(divTemp.firstElementChild);179 });180 181 // 渲染182 itemsDOM.appendChild(fragment);183 }
View Code

 

转载于:https://www.cnblogs.com/imwtr/p/10051995.html

你可能感兴趣的文章
springcloud(十三):Eureka 2.X 停止开发,但注册中心还有更多选择:Consul 使用详解...
查看>>
关于Boolean类型做为同步锁异常问题
查看>>
TestLink运行环境:Redhat5+Apache2.2.17+php-5.3.5+MySQL5.5.9-1
查看>>
Get File Name from File Path in Python | Code Comments
查看>>
显示本月每一天日期
查看>>
[转]java 自动装箱与拆箱
查看>>
NET的堆和栈04,对托管和非托管资源的垃圾回收以及内存分配
查看>>
think in coding
查看>>
IdHttpServer实现webservice
查看>>
HTML的音频和视频
查看>>
Unsupported major.minor version 52.0
查看>>
面对对象之差异化的网络数据交互方式--单机游戏开发之无缝切换到C/S模式
查看>>
优酷网架构学习笔记
查看>>
把HDFS里的json数据转换成csv格式
查看>>
WEEX-EROS | 集成并使用 bindingx
查看>>
广州牵引力来告诉你学编程先学什么语言好?
查看>>
广州牵引力总结初学者怎样学好UI设计?
查看>>
使用Metrics方法级远程监控Java程序
查看>>
Spring核心系列之Bean的生命周期
查看>>
VasSonic源码之并行加载
查看>>