瀑布流布局
文章目录
一、瀑布流介绍
1、什么是瀑布流
瀑布流,又称瀑布流式布局。是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部。即多行等宽元素排列,后面的元素依次添加到其后,等宽不等高,根据图片原比例缩放直至宽度达到我们的要求,依次按照规则放入指定位置。
2、为什么使用瀑布流
瀑布流布局在我们现在的前端页面中经常会用的到,它可以有效的降低页面的复杂度,节省很多的空间,对于整个页面不需要太多的操作,只需要下拉就可以浏览用户需要看到的数据;并且,瀑布流可以提供很好的用户体验,通过结合下拉刷新,上拉加载进行数据的懒加载等操作,对于用户的体验感来说是接近于满分的!
3、瀑布流的特点
其实瀑布流的特点就是参差不齐的排列方式,以及流式布局的扩展性,可以通过界面展示给用户多条数据,并且让用户可以有向下浏览的冲动。
4、瀑布流优点
节省空间,外表美观,更有艺术性。
对于手机端设备非常友好,通过向上滑动浏览。
用户浏览时的观赏和思维不容易被打断。
5、瀑布流缺点
用户无法了解内容总长度,对内容没有宏观掌控。
用户无法了解现在所处的具体位置,不知道离终点还有多远。
回溯时不容易定位到之前看到的内容。
容易造成页面加载的负荷。
容易造成用户浏览的疲劳,没有短暂的休息时间。
二、示例图片与网址
二、代码实现方式
1.pc端js计算高度
思路:
1.获取要加载的元素,取第一个元素根据宽度计算视图窗口能展示几列。
2.根据能展示的列数设初始高度值。
3.遍历要排序的元素,判断最后一列高度比较找到高度最小的那个。
4.将当前元素定位到此处,更新当前列的高度
代码如下(示例):
// 初始化图片位置
var init = () => {
// 1、获取所有的盒子 宽度都是固定的高度自适应
var node = document.querySelectorAll('.item');
// 2、获取第一个盒子的宽度+外边距
var nodeWidth = node[0].offsetWidth + 10;
// 3、这里根据浏览器视口大小进行动态更新展示一排显示的个数
var colCount = parseInt(document.body.offsetWidth / nodeWidth);
// 4、定义一个数组保存最后一排的高度
var colItemHeight = [];
// 5、开始默认第一排都是为0
for (var j = 0; j < colCount; j++) {
colItemHeight.push(0);
}
// 6、遍历所有的盒子
node.forEach(function (item) {
// 7、假设第一排第一个为最小的高度
var minHeight = colItemHeight[0];
// 8、保存最小高度盒子的索引值
var index = 0;
// 9、遍历最新高度的数组
colItemHeight.forEach(function (pro, idx) {
// 10、判断最小高度是不是大于当前遍历到的高度
if (minHeight > pro) {
// 11、如果条件成立 将当前最小的高度重新复制给最小高度变量
minHeight = pro;
// 12、同时更新当前最小高度盒子的索引
index = idx;
}
})
// 13、获取到最小高度的盒子后 开始设置盒子的定位
item.style.top = minHeight + 'px';
item.style.left = (nodeWidth * index) + 'px';
// 14、动态更新,最新高度等于 盒子的高度+外边距+之前高度
colItemHeight[index] = (item.offsetHeight + 10) + colItemHeight[index];
})
}
2.css实现
思路:
column-width: 200px;
//把元素中的文本划分为几列布局
column-count: auto;
//指定列之间的的间隙:
column-gap: 40px;
代码如下(示例):
.waterfall {
column-width: 200px;
column-count: auto;
column-gap: 1rem;
}
3.createSelectorQuery节点查询计算高度
思路:
根据createSelectorQuery 获取当前节点
分为左右两侧盒子,循环计算高度添加到两侧
代码如下(示例):
const getDataDom = async () => {
// Taro.showLoading({
// title: "数据加载中",
// mask: true,
// });
let _leftList = [],
_rightList = [];
for (let item in data) {
// 要有固定内容先将内容判断高度。
await getBoxHeight(_leftList, _rightList);
// 判断两边的高度
// console.log(leftHeightRef.current, rightHeightRef.current)
if (leftHeightRef.current <= rightHeightRef.current) {
_leftList.push(data[item]);
setLeftList([..._leftList]);
} else {
_rightList.push(data[item]);
setRightList([..._rightList]);
}
}
// Taro.hideLoading()
};
const getBoxHeight = () =>
new Promise((resolve, reject) => {
query = Taro.createSelectorQuery();
query.select("#dis_left").boundingClientRect();
query.select("#dis_right").boundingClientRect();
// 处理异步问题,没有数据
setTimeout(() => {
query.exec((res) => {
// console.log(res, res[0].height, res[1].height)
leftHeightRef.current = res[0].height; //获取左边列表的高度
rightHeightRef.current = res[1].height; //获取右边列表的高度
resolve();
});
});
});