文章目录
前言
瀑布流布局是网页设计常见的一种布局,一般用于图片多列展示。列宽固定,图片根据自身高度自适应交错排列。
一、实现原理
通过动态计算哪一列高度最低,就把图片放置该列下显示,直至所有图片分列完毕
计算哪一列高度最低具体实现过程又分2种方式:
方式1:通过计算每一列每张图片渲染后高度进行累加就是该列的高度,记录每列累加高度比较大小
方式2:直接通过图片父级元素高度(列div)来判断哪一列最低
区别:方式1无需等待图片真实渲染完成在比较高度,方式2需要等待图片真实渲染完成在获取高度
二、代码实现
以左右2列为例
<template><divclass="page"><!-- 左图片列表 --><divclass="left"ref="left"><imgclass="img"v-for="(item, index) in leftList":key="index":src="item"/></div><!-- 右图片列表 --><divclass="right"ref="right"><imgclass="img"v-for="(item, index) in rightList":key="index":src="item"/></div></div></template>
<stylescoped>.page{width: 100%;display: flex;align-items: flex-start;padding: 0 1%;box-sizing: border-box;}.left,
.right{margin: 0 auto;width: 48%;}.img{width: 100%;height: auto;margin-bottom: 10px;}</style>
1.方式1(图片高度累加比较法)
<script>exportdefault{data(){return{imgList:["https://img0.baidu.com/it/u=1345303087,1528317222&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1082","https://img2.baidu.com/it/u=1893470775,4143435497&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500","https://img0.baidu.com/it/u=1088754973,1390499664&fm=253&fmt=auto&app=138&f=JPEG?w=335&h=500","https://img1.baidu.com/it/u=3866290852,3566512524&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500","https://img2.baidu.com/it/u=1114729443,1120710416&fm=253&fmt=auto&app=138&f=JPEG?w=667&h=500","https://img0.baidu.com/it/u=1345303087,1528317222&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1082","https://img2.baidu.com/it/u=1893470775,4143435497&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500","https://img2.baidu.com/it/u=1088754973,1390499664&fm=253&fmt=auto&app=138&f=JPEG?w=335&h=500",],//所有图片leftList:[],//左边列图片rightList:[],//右边列图片leftHeight:0,//左边列高度rightHeight:0,//右边列高度columnWidth:0,//列宽度};},mounted(){this.$nextTick(()=>{this.columnWidth =this.$refs.left.clientWidth;this.setWaterFallLayout();});},methods:{//方法1asyncsetWaterFallLayout(){for(let item ofthis.imgList){let img =newImage();
img.src = item;try{let h =awaitthis.getImgHeight(img);//图片渲染后高度if(this.leftHeight <=this.rightHeight){//左边列比右边低,图片放入左边this.leftList.push(item);this.leftHeight += h;}else{//否则,图片放入右边this.rightList.push(item);this.rightHeight += h;}}catch(e){
console.log(e)}}},//获取图片高度getImgHeight(img){returnnewPromise((resolve,reject)=>{//图片加载完成
img.onload=()=>{let h =(img.height / img.width)*this.columnWidth;//计算图片渲染后高度resolve(h);};//加载出错
img.onerror=()=>{reject('error')}});},},};</script>
2.方式2(父元素高度比较法)
每次放入图片需要等待渲染后再重新计算父元素高度,关键代码 await this.$nextTick()
<script>exportdefault{data(){return{imgList:["https://img0.baidu.com/it/u=1345303087,1528317222&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1082","https://img2.baidu.com/it/u=1893470775,4143435497&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500","https://img0.baidu.com/it/u=1088754973,1390499664&fm=253&fmt=auto&app=138&f=JPEG?w=335&h=500","https://img1.baidu.com/it/u=3866290852,3566512524&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500","https://img2.baidu.com/it/u=1114729443,1120710416&fm=253&fmt=auto&app=138&f=JPEG?w=667&h=500","https://img0.baidu.com/it/u=1345303087,1528317222&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1082","https://img2.baidu.com/it/u=1893470775,4143435497&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500","https://img2.baidu.com/it/u=1088754973,1390499664&fm=253&fmt=auto&app=138&f=JPEG?w=335&h=500",],//所有图片leftList:[],//左边列表图片rightList:[],//右边列表图片};},mounted(){this.$nextTick(()=>{this.setWaterFallLayout2();});},methods:{//方法2asyncsetWaterFallLayout2(){for(let item ofthis.imgList){if(this.$refs.left.clientHeight <=this.$refs.right.clientHeight){//左边列比右边低,图片放入左边this.leftList.push(item);}else{//否则图片放入右边this.rightList.push(item);}awaitthis.$nextTick();//等待渲染完成后重新比较左右高度}},},};</script>
三.uniapp实现
由于uniapp获取元素高度和vue有所区别,造成实现瀑布流方式也需要调整。我们知道uniapp不能通过this.$ref.xx.clientHeight获取元素高度,而需要通过uni.createSelectorQuery().in(this).select(‘.xxxx’).boundingClientRect().exec()来获取,且经过实测当图片动态加入列后通过该api计算出父元素真实高度是不准确的,所以uniapp瀑布流布局实现方式只能通过方法1(也即图片高度累加法)进行实现,除了上面方法1通过img.onload来获取图片高度外,uniapp还提供uni.getImageInfo方法来更方便获取图片高度。
代码实现
<template><viewclass="page"><viewclass="left"ref="left"><imageclass="image"v-for="(item,i) in leftList":key="i":src="item"mode="widthFix"></image></view><viewclass="right"ref="right"><imageclass="image"v-for="(item,i) in rightList":key="i":src="item"mode="widthFix"></image></view></view></template>
<stylelang="scss">.page{width: 100%;display: flex;align-items: flex-start;padding: 0 1%;box-sizing: border-box;}.left,
.right{margin: 0 auto;width: 48%;}.image{width: 100%;height: auto;margin-bottom: 10px;}</style>
<script>exportdefault{data(){return{imageList:["https://img0.baidu.com/it/u=1345303087,1528317222&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1082","https://img2.baidu.com/it/u=1893470775,4143435497&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500","https://img0.baidu.com/it/u=1088754973,1390499664&fm=253&fmt=auto&app=138&f=JPEG?w=335&h=500","https://img1.baidu.com/it/u=3866290852,3566512524&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500","https://img2.baidu.com/it/u=1114729443,1120710416&fm=253&fmt=auto&app=138&f=JPEG?w=667&h=500","https://img0.baidu.com/it/u=1345303087,1528317222&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1082","https://img2.baidu.com/it/u=1893470775,4143435497&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500","https://img0.baidu.com/it/u=1088754973,1390499664&fm=253&fmt=auto&app=138&f=JPEG?w=335&h=500",],//所有图片leftList:[],//左边列图片rightList:[],//右边列图片leftHeight:0,//左边列高度rightHeight:0,//右边列高度columnWidth:0//列宽度}},mounted(){this.$nextTick(()=>{
uni.createSelectorQuery().in(this).select('.left').boundingClientRect(res=>{this.columnWidth = res.width
//方法1this.setWaterFallLayout()//方法2// this.setWaterFallLayout2()}).exec()})},methods:{//方法1通过img.onloadasyncsetWaterFallLayout(){for(let item ofthis.imageList){let img =newImage()
img.src = item
try{let h =awaitthis.getImgHeight(img)if(this.leftHeight <=this.rightHeight){this.leftList.push(item)this.leftHeight += h
}else{this.rightList.push(item)this.rightHeight += h
}}catch(e){
console.log(e)}}},//获取图片高度getImgHeight(img){returnnewPromise((resolve, reject)=>{
img.onload=()=>{let h = img.height / img.width *this.columnWidth
resolve(h)}//加载出错
img.onerror=()=>{reject('error')}})},//方法2通过uni.getImageInfoasyncsetWaterFallLayout2(){for(let item ofthis.imageList){
uni.getImageInfo({src: item,success:e=>{if(this.leftHeight <=this.rightHeight){this.leftList.push(item)this.leftHeight += e.height
}else{this.rightList.push(item)this.rightHeight += e.height
}}})}}},}</script>
四、多列实现
多列实现和2列一样,动态生成每列图片数据和记录每列高度
代码实现
以最简单的父元素高度比较法(方式2)为例实现,图片高度累加比较法(方式1)自行类比实现
<template><divclass="page"><divclass="column"ref="column"v-for="(item, index) in columnList":key="index"><imgclass="img"v-for="(n, i) in item":key="i":src="n"/></div></div></template>
<stylescoped>.page{width: 100%;display: flex;align-items: flex-start;padding: 0 1%;box-sizing: border-box;}.column{flex: 1;padding: 0 10px;box-sizing: border-box;width: 0;}.img{width: 100%;height: auto;margin-bottom: 10px;}</style>
<script>exportdefault{data(){return{imgList:["https://img0.baidu.com/it/u=1345303087,1528317222&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1082","https://img2.baidu.com/it/u=1893470775,4143435497&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500","https://img0.baidu.com/it/u=1088754973,1390499664&fm=253&fmt=auto&app=138&f=JPEG?w=335&h=500","https://img1.baidu.com/it/u=3866290852,3566512524&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500","https://img2.baidu.com/it/u=1114729443,1120710416&fm=253&fmt=auto&app=138&f=JPEG?w=667&h=500","https://img0.baidu.com/it/u=1345303087,1528317222&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1082","https://img2.baidu.com/it/u=1893470775,4143435497&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500","https://img0.baidu.com/it/u=1088754973,1390499664&fm=253&fmt=auto&app=138&f=JPEG?w=335&h=500","https://img0.baidu.com/it/u=1345303087,1528317222&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1082","https://img2.baidu.com/it/u=1893470775,4143435497&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500",],//所有图片columnList:[],//分配后的每列图片columWidth:0,//每列宽度columnCount:5,//显示几列};},created(){//初始化数据for(let i =0; i <this.columnCount; i++){this.columnList.push([]);//生成每列图片数组}},mounted(){this.$nextTick(()=>{this.setWaterFallLayout();})},methods:{//瀑布布局asyncsetWaterFallLayout(){for(let item ofthis.imgList){let columnHeight =this.$refs.column.map((item)=> item.clientHeight);//每列高度数组let min = Math.min(...columnHeight);//找出最小高度值let index = columnHeight.findIndex((item)=> item === min);//找出最小高度列的索引this.columnList[index].push(item);//放入图片awaitthis.$nextTick();//等待渲染完成后重新比较高度}},},};</script>
版权归原作者 pixle0 所有, 如有侵权,请联系我们删除。