分享一个Vue实现图片水平瀑布流的插件

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

分享一个Vue实现图片水平瀑布流的插件

文章插图
一.需求来源今天碰到了一个需求 , 需要在页面里 , 用水平瀑布流的方式,将一些图片进行加载 , 这让我突然想起我很久以前写的一篇文章《JS两种方式实现水平瀑布流布局》但是有个问题,这个需求是Vue项目的 , 那没办法,这里给大家分享下我的开发过程,项目主体用的是之前在学习的CRMEB的后端框架来开发,UI使用iView-UI,其余的场景与其他的vue项目一致二.逻辑设想如果不是vue环境,我们的逻辑为1.获取所有的div元素2.获取盒子的宽度,宽度都是相同,高度不同3.在浮动布局中每一行的盒子个数不固定,是根据屏幕宽度和盒子宽度决定4.获取屏幕宽度5.求出列数 , 屏幕宽度 / 盒子宽度 取整6.瀑布流最关键的是第二行的盒子的排布方式,通过获取第一行盒子中最矮的一个的下标,绝对定位,top是最矮盒子的高度,left是最矮盒子的下标 * 盒子的宽度7.循环遍历所有的盒子 , 通过列数找到第一行所有的盒子,将第一行盒子的高度放入数组,再取出数组中最小的一个的下标 , 就是第6步思路的第一行盒子中最矮盒子的下标 。8.循环继续 , 第二行第一个盒子,通过绝对定位 , 放进页面 。9.关键 , 需要将数组中最小的值加上放进的盒子的高度10.继续循环,遍历所有11.如果想要加载更多,需要判断最后一个盒子的高度和页面滚动的距离 , 再将数据通过创建元素 , 追加进页面 , 再通过瀑布流布局展示但如果是Vue项目,我们可以把逻辑归结为以下几步1.获取屏幕宽度2..获取盒子的宽度,宽度都是相同,高度不同3.在浮动布局中每一行的盒子个数不固定 , 是根据屏幕宽度和盒子宽度决定4.求出列数 , 屏幕宽度 / 盒子宽度 取整5.瀑布流最关键的是第二行的盒子的排布方式 , 通过获取第一行盒子中最矮的一个的下标 , 绝对定位 , top是最矮盒子的高度 , left是最矮盒子的下标 * 盒子的宽度6.继续循环,遍历所有7.如果想要加载更多,需要判断最后一个盒子的高度和页面滚动的距离,再将数据通过创建元素,追加进页面,再通过瀑布流布局展示三.最终效果图片
分享一个Vue实现图片水平瀑布流的插件

文章插图
四.代码分析先看下我的html部分<template><div class="tab-container" id="tabContainer"><div class="tab-item" v-for="(item, index) in pbList" :key="index"><img :src="https://www.huyubaike.com/biancheng/item.url" /></div></div></template><style scoped>* {margin: 0;padding: 0;}/* 最外层大盒子 */.tab-container {padding-top: 20px;position: relative;}/* 每个小盒子 */.tab-container .tab-item {position: absolute;height: auto;border: 1px solid #ccc;box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);background: white;/* 元素不能中断显示 */break-inside: avoid;text-align: center;}.tab-container .tab-item img {width: 100%;height: auto;display: block;}</style>核心js部分<script>export default {name:'compList',props:{pbList:{type:Array,default:()=>{return []}}},data() {return {};},mounted() {this.$nextTick(()=>{this.waterFall("#tabContainer", ".tab-item"); //实现瀑布流})},methods: {waterFall(wrapIdName,contentIdName,columns = 5,columnGap = 20,rowGap = 20) {// 获得内容可用宽度(去除滚动条宽度)const wrapContentWidth =document.querySelector(wrapIdName).offsetWidth;// 间隔空白区域const whiteArea = (columns - 1) * columnGap;// 得到每列宽度(也即每项内容宽度)const contentWidth = parseInt((wrapContentWidth - whiteArea) / columns);// 得到内容项集合const contentList = document.querySelectorAll(contentIdName);// 成行内容项高度集合const lineConentHeightList = [];for (let i = 0; i < contentList.length; i++) {// 动态设置内容项宽度contentList[i].style.width = contentWidth + "px";// 获取内容项高度const height = contentList[i].clientHeight;if (i < columns) {// 第一行按序布局contentList[i].style.top = "0px";contentList[i].style.left = contentWidth * i + columnGap * i + "px";// 将行高push到数组lineConentHeightList.push(height);} else {// 其他行// 获取数组最小的高度 和 对应索引let minHeight = Math.min(...lineConentHeightList);let index = lineConentHeightList.findIndex((listH) => listH === minHeight);contentList[i].style.top = minHeight + rowGap +"px";contentList[i].style.left = (contentWidth + columnGap) * index + "px";// 修改最小列的高度 最小列的高度 = 当前自己的高度 + 拼接过来的高度 + 行间距lineConentHeightList[index] += height + rowGap;}}},},};</script>

推荐阅读