html木桶布局,木桶布局 实现

57ac6677dd9c

百度图片

图片来自 百度图片

像这样高度一样,而宽度不同的布局方式称之为木桶布局。它有几个鲜明的特点: 每行的图片高度一致;每行的图片都是占满的。

如何实现木桶布局 之 整体思路

我们需要先拥有一些素材(图片), 并且将这些图片横向摆放到页面上。假如我现在有100张图片,并且编号1~100, 它们的宽高都不是固定的。现在我们需要将图片都摆放到目标页面上。

首先,我们每行的高度是事先设定的,所以我们在把图片放入每一行(row)的时候,需要先调整图片的大小(等比例放大或缩小)使得图片的高度与行容器的高度一致 —— 即下图中的蓝色方框。

其中: 橙色方框代表图片(假设已和蓝色方框等高), 黑色数字代表图片编号。

依次往行容器中放置等比例大小调整过的图片,①号图片,②号图片,...,一直到⑤号图片,发现⑤号图片它放不下了。这时候我们就需要把这个⑤号图片放到下一行的开头,并且再次调整图片大小,使得第一行中的①号-④号图片能够撑满第一行。该次调整主要是调整图片的高度,使得其宽度能够自适应撑满该行。

如果测量一下百度图片每行的高度就会发现: 每行高度基本相等,但有几像素的差距。

57ac6677dd9c

木桶布局原理

然后重复上述步骤,直至图片摆放完毕。

木桶布局代码实现 之 具体步骤

从HTML、CSS、JS部分依次实现。

大概有个结构,就是先有一个固定宽度的父容器,与若干个(数量未定的)行容器来盛放每行的图片数量,然后每行有若干个图片容器来盛放图片。

父子关系(父 > 子): 固定宽度的父容器 (" .ct ") > 行容器(" .img-row ") > 图片容器(" .img-box ")

对应上图(木桶布局原理)为: 红色方框 > 蓝色方框 > 橙色方框

/* CSS */

/* 页面布局容器*/

.ct {

width: 1000px;

margin: 0 auto;

}

/* 图片容器 */

.img-box {

float: left;

}

/* 行容器 清楚子元素(图片容器)的浮动*/

.img-row::after {

content: "";

display: block;

clear: both;

}

JS代码

这里采用构造函数创建对象的方式来写这段代码,注意按照约定构造函数的首字母要大写。创建一个新对象,然后将构造函数的作用域赋给新对象,调用构造函数中的方法。

函数名声明为 Barrel ,意为木桶。然后就要确定有哪些属性和方法。在理解了思路步骤的前提下,可以构思需要哪些属性、方法以及它们的作用。

属性:

每行图片的高度固定: rowHeight, 行高

拥有一个固定的容器: DOM对象,一个容器 命名为 .ct。 还应该有行容器和图片容器,但是由于这两个容器内容数量不固定,所以在布局的时候再创建

行容器的宽度: width, 获取ct的宽度

存放每行图片的数组: imgArr[]。每次把加载的图片压入该数组,判断该行是否超出宽度。

方法:

拥有素材图片 : 通过getImgUrls()方法来获取图片链接,(或从数据库中获取图片)。这里是通过访问https://placeholder.com/ 网站来获取代码,具体后述

加载图片信息: loadImg()方法来加载图片,以便获取图片信息,

渲染图片队列: render() 改变图片的比例大小,计算一行可以放置多少个图片

放置图片位置: layout() 将改变完大小的图片放置到页面上,append到对应的DOM元素节点上。具体关系对应前面的父子关系即可

初步的代码结构就如下所示:

function Barrel(ct, imgNum, height) {

this.ct = ct; // 木桶布局容器的DOM节点

this.width = parseInt(window.getComputedStyle(ct, null).getPropertyValue("width")); // 行宽,由于获取到的值是string: 1000px 所以转化为数值 1000

this.rowHeight = height; // 行高

this.imgArr = []; // 存放每行图片的数组

this.loadImg(imgNum);

}

Barrel.prototype = {

getImgUrls: function(){},

loadImg: function(){},

render: function(){},

layout: function(){}

}

方法实现:

getImgUrls()方法:首先可以访问该网站 ,可以获取到占位图片,可以看到获取占位图片的格式 : http://via.placeholder.com/width x height /ffffff/00000/ , width与height分别代表图片的宽高,fffff是图片的背景颜色,000000是图片的文本颜色。

随机生成图片的大小(宽高限定一个范围),背景颜色与文本颜色。这里添加一个参数,imgNum:确定需要图片的数量。最后返回包含这些图片链接的一个数组

getImgUrls: function(imgNum){

let imgUrls = [];

let colorArr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "A", "B", "C", "D", "E", "F"]; // 颜色数组[0-9, A-F],

// 该颜色数组生成与源代码稍有不同,在我的GitHub上是用for循环生成的

for(let i = 0; i < imgNum; i++) {

let imgWidth = Math.floor(Math.random()*50+50); // 设定宽度50-100

let imgHeight = Math.floor(Math.random()*30+50); // 设定高度为30-80

let bgColor = textColor = ""; // 下面使用的是字符串拼接,每次使用都需要重新清空

for(let j=0; j < 6; j++){

bgColor += colorArr[Math.floor(Math.random()*16)];

textColor += colorArr[Math.floor(Math.random()*16)];

}

let url = "http://via.placeholder.com/" + imgWidth + "x" + imgHeight + "/" + bgColor + "/" + textColor;

imgUrls.push(url);

}

return imgUrls;

}

loadImg() 方法:用来加载图片,图片来源就从已有素材中寻找。即getImgUrls()

在这个方法中,需要做的就是获取图片信息(宽高,src等)并改变大小,高度与行高一致,宽度等比例改变。并且将信息存储起来,等每张图片加载完毕后就加入渲染排列图片的队列中。

loadImg: function(imgNum){

let imgUrlsArr = this.getImgUrls(imgNum);

let _this = this; // 保存this指针的指向,方便调用属性及方法

for(let i = 0; i < imgNum; i++){

let newImg = new Image(); // 新建图片对象

newImg.src = imgUrlsArr[i]; // 加载图片内容

newImg.onload = function(){

// Image对象加载了src后拥有宽高属性, imgInfo存储图片信息

let ratio = this.width / this.height;

let imgInfo = {

target: this, // 用来存放当前目标newImg,方便后续调用

height: _this.rowHeight,

width: ratio * _this.rowHeight, // 等比例缩放

ratio: ratio,

};

// 把加载完的图片加入渲染队列

_this.render(imgInfo);

}

}

},

render()方法:渲染队列的方法,主要是判断图片能否放在一行上(每次把图片加入到imgArr队列中就可判断长度),并当图片符合占满一行的条件时,将最后一张图片放到下一行,并记录需要改变的图片比例交由layout()方法更改。

render: function(imgInfo){

// 定义该行图片宽度之和

let wholeWidth = 0;

this.imgArr.push(imgInfo);

for(let i = 0; i < this.imgArr.length; i++){

wholeWidth += this.imgArr[i].width;

}

// 如果该行加入的图片宽度大于了该行的宽度

// 就需要弹出最后一张图片,并更改前面的图片大小比例

if(wholeWidth > this.width){

let lastImg = this.imgArr.pop();

wholeWidth -= lastImg.width;

// 利用面积相等原则,来计算新的高度

let newHeight = this.width * this.rowHeight / wholeWidth;

this.layout(newHeight);

// 放置完毕之前的图片之后,清空该图片队列

// 并将上一行溢出的图片 作为下一行的第一张

this.imgArr = [];

this.imgArr.push(lastImg);

}

}

layout()方法:获得newHeight参数,是图片的新高度,改变该行图片的高度,使得这些图片自适应改变宽度之后能占满该行。也就是说这个木桶布局的高度会发生变化 与之前设定的this.rowHeight相近但不相等。

之后创建节点,并把修改好的图片依次加入到创建好的节点上,然后添加到页面中。

layout: function(newHeight){

// 一次只放一行, 所以只生成一个imgRow

let imgRow = document.createElement("div");

imgRow.classList.add("img-row");

// 一行包含若干个图片,所以需要若干个imgBox,并将图片加入其中

for(let i = 0; i < this.imgArr.length; i++){

let imgBox = document.createElement("div");

imgBox.classList.add("img-box");

let img = this.imgArr[i].target;

// 改变了高度之后宽度自己会跟着改变

img.style.height = newHeight + "px"; // 注意加"px"

imgBox.appendChild(img);

imgRow.appendChild(imgBox);

}

// 先把图片加载到图片盒子里,然后加到图片列中,最后加到容器中

this.ct.appendChild(imgRow);

}

最后便是两行代码来运行这段程序

let ct = document.querySelector(".ct");

let barrel = new Barrel(ct, 100, 100); // 100张图片数量, 指定每行的初始行高为100

效果预览及代码地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值