前言
小白实战\]-JS瀑布流-大厂图片页面布局实战
# 正文
今天我们来学习一个大厂都在用的瀑布流布局!!
首先,我们看一个案例
 像我们平时看到的这种页面,是如何把各种不同大小的图片如此整齐的放在一个页面当中的呢?
当然是--瀑布流!!!
## 什么是瀑布流?
在JavaScript中,瀑布流(Waterfall)是一种常见的页面布局方式,它让内容以列的形式排列,但每一列的宽度可以根据视口宽度动态调整。这种方式使得页面在各种设备上(如手机、平板、桌面)都能很好地展示。
在实现上,瀑布流布局通常会使用JavaScript来动态计算每一列的宽度,并使用CSS来控制布局。有时也会结合使用一些JavaScript库或框架,如Masonry、Isotope等,这些库提供了更高级的功能,如动画效果、过滤、排序等。
瀑布流布局的主要特点是:
1. 列宽自适应:每一列的宽度根据视口宽度动态调整,以适应不同设备的显示。
2. 列数固定:每一列中的项目数量通常是固定的,这样可以保证每一列的显示效果。
3. 无空隙:瀑布流布局通常会尽量消除列与列之间的空隙,以提高页面的显示效果。
4. 无限滚动:与传统的分页方式不同,瀑布流布局通常采用无限滚动的方式,即用户可以一直向下滚动来查看更多的内容。
我们如何实现这种页面布局方式呢?
我们需要两个文件一个是`html`,`js`文件
## 实现`HTML`文件
```html
js瀑布流
```
在我们的`html`文件中,我们定义了`id`为`container`的容器,里面装了十个`box`容器,每个`box`中都放了一个图片!
在头部定义一个`style`中设计样式。
1. `*{margin: 0; padding: 0;}`:将页面上所有元素的边距(margin)和填充(padding)设置为0。初始化页面!
2. `#container{position: relative;}`:`id`为"container"的元素的定位设置为相对定位(relative)。为其子容器作为参考!
3. `.box{float: left; padding: 5px;}`:将`class`为"box"的元素的浮动设置为左浮动(left),这些元素将排列在其容器的左侧,并与其右侧的元素相邻。同时,这些元素的内部周围增加了5像素的填充。
4. `.box-img{width: 150px; padding: 5px; border: 1px solid #ccc;}`:将`class`为"box-img"的元素的宽度设置为150像素,内部周围增加了5像素的填充,并添加了一个1像素宽、颜色为浅灰色的边框。
5. `img{width: 100%;}`:将页面上所有图像的宽度设置为100%,以适应其父元素的宽度。
## 实现js文件
首先,我们定义一个`imgLocation(parent, content)`函数
1. `function imgLocation(parent, content)`: 定义一个函数,接受两个参数,分别是元素的ID (`parent`) 和子元素的ID或类名 (`content`)。
2. `var cparent = document.getElementById(parent)`: 通过ID获取元素。
3. `var ccontent = getChildElement(cparent, content)`: 调用 `getChildElement` 函数获取 `cparent` 的子元素,这个子元素可能是通过ID或类名指定的。
4. `var imgWidth = ccontent[0].offsetWidth`: 获取第一个子元素的宽度。
5. `var num = Math.floor(document.documentElement.clientWidth / imgWidth)`: 计算可以放下多少张图片,这是通过将浏览器视口的宽度除以每张图片的宽度并向下取整得到的。
6. `cparent.style.cssText = 'width: ${imgWidth * num}px'`: 设置 `cparent` 的宽度,使其能够容纳 `num` 张图片。
7. 定义一个数组 `BoxHeightArr` 来存储每列图片的高度。
8. 对于 `ccontent` 中的每一张图片:
* 如果当前的图片索引小于 `num`(即图片还没有超过可以容纳的数量),则将该图片的高度添加到 `BoxHeightArr` 中。
* 如果当前的图片索引大于等于 `num`(即图片已经超过可以容纳的数量),则需要执行以下操作: a. 找到 `BoxHeightArr` 中最小的高度。 b. 找到该最小高度的索引。 c. 将该图片绝对定位,并将其顶部设置为最小高度,左侧设置为对应最小高度的图片的左侧位置。 d. 更新这一列的高度,将新图片的高度也加进去。
这个函数依赖于一个名为 `getChildElement` 的函数
于是我们的函数代码可以这样写:
```js
function imgLocation(parent, content) { // 当前有多少张图片要摆放
var cparent = document.getElementById(parent)
var ccontent = getChildElement(cparent, content)
var imgWidth = ccontent[0].offsetWidth
var num = Math.floor(document.documentElement.clientWidth / imgWidth)
cparent.style.cssText = `width: ${imgWidth * num}px`
var BoxHeightArr = []
for (var i = 0; i < ccontent.length; i++) {
if (i < num) {
BoxHeightArr[i] = ccontent[i].offsetHeight
} else { // 要操作的图
var minHeight = Math.min.apply(null, BoxHeightArr)
// minHeight 是第几张
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] = BoxHeightArr[minIndex] + ccontent[i].offsetHeight
}
}
console.log(num);
}
```
然后,我们接下来实现`getChildElement(parent, content)`函数!
1. 首先,定义一个空数组 `contentArr`,用于存储所有找到的符合条件的子元素。
2. 使用 `parent.getElementsByTagName('*')` 获取父元素下所有的子元素,并将这些子元素存储在 `allContent` 变量中。这里,`getElementsByTagName('*')` 是用来选择所有的子元素的,不论是哪种类型的元素。
3. 使用 `for` 循环遍历所有子元素。对于每一个子元素,检查它的 `className` 属性是否与 `content` 参数相等。`className` 是用来获取或设置元素的类名的属性。
4. 如果一个子元素的 `className` 属性与 `content` 参数相等,那么就使用 `push` 方法将这个子元素添加到 `contentArr` 数组中。
5. 最后,函数返回 `contentArr` 数组,这个数组中包含了所有符合条件的子元素。
于是我们代码可以这样写:
```js
function imgLocation(parent, content) { // 当前有多少张图片要摆放
var cparent = document.getElementById(parent)
var ccontent = getChildElement(cparent, content)
var imgWidth = ccontent[0].offsetWidth
var num = Math.floor(document.documentElement.clientWidth / imgWidth)
cparent.style.cssText = `width: ${imgWidth * num}px`
var BoxHeightArr = []
for (var i = 0; i < ccontent.length; i++) {
if (i < num) {
BoxHeightArr[i] = ccontent[i].offsetHeight
} else { // 要操作的图
var minHeight = Math.min.apply(null, BoxHeightArr)
// minHeight 是第几张
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] = BoxHeightArr[minIndex] + ccontent[i].offsetHeight
}
}
console.log(num);
}
function getChildElement(parent, content) {
var contentArr = []
var allContent = parent.getElementsByTagName('*')
for (var i = 0; i < allContent.length; i++) {
if (allContent[i].className == content) {
contentArr.push(allContent[i])
}
}
return contentArr
}
```
最后,我们的`js`文件就可以写成这样啦!
```js
// // 读取用户屏幕第一行放了多少张图
// 操作下一张图,找到上一行最矮的高度,将图片排放到其下方
imgLocation('container', 'box')
function imgLocation(parent, content) { // 当前有多少张图片要摆放
var cparent = document.getElementById(parent)
var ccontent = getChildElement(cparent, content)
var imgWidth = ccontent[0].offsetWidth
var num = Math.floor(document.documentElement.clientWidth / imgWidth)
cparent.style.cssText = `width: ${imgWidth * num}px`
var BoxHeightArr = []
for (var i = 0; i < ccontent.length; i++) {
if (i < num) {
BoxHeightArr[i] = ccontent[i].offsetHeight
} else { // 要操作的图
var minHeight = Math.min.apply(null, BoxHeightArr)
// minHeight 是第几张
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] = BoxHeightArr[minIndex] + ccontent[i].offsetHeight
}
}
console.log(num);
}
function getChildElement(parent, content) {
var contentArr = []
var allContent = parent.getElementsByTagName('*')
for (var i = 0; i < allContent.length; i++) {
if (allContent[i].className == content) {
contentArr.push(allContent[i])
}
}
return contentArr
}
```
## 最后:我们展示一下效果!!

好啦!我们的瀑布流布局就这样成功实现啦!!!
如果大家有任何想法和指正,欢迎在评论区留言!!点个小小的赞支持一下吧!🌹🌹🌹