vue+uniapp瀑布流布局多種實(shí)現(xiàn)方式示例代碼
前言
瀑布流布局是網(wǎng)頁(yè)設(shè)計(jì)常見(jiàn)的一種布局,一般用于圖片多列展示。列寬固定,圖片根據(jù)自身高度自適應(yīng)交錯(cuò)排列。

一、實(shí)現(xiàn)原理
通過(guò)動(dòng)態(tài)計(jì)算哪一列高度最低,就把圖片放置該列下顯示,直至所有圖片分列完畢
計(jì)算哪一列高度最低具體實(shí)現(xiàn)過(guò)程又分2種方式:
方式1:通過(guò)計(jì)算每一列每張圖片渲染后高度進(jìn)行累加就是該列的高度,記錄每列累加高度比較大小
方式2:直接通過(guò)圖片父級(jí)元素高度(列div)來(lái)判斷哪一列最低
區(qū)別:方式1無(wú)需等待圖片真實(shí)渲染完成在比較高度,方式2需要等待圖片真實(shí)渲染完成在獲取高度
二、代碼實(shí)現(xiàn)
以左右2列為例
<template>
<div class="page">
<!-- 左圖片列表 -->
<div class="left" ref="left">
<img
class="img"
v-for="(item, index) in leftList"
:key="index"
:src="item"
/>
</div>
<!-- 右圖片列表 -->
<div class="right" ref="right">
<img
class="img"
v-for="(item, index) in rightList"
:key="index"
:src="item"
/>
</div>
</div>
</template>
<style scoped>
.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>
export default {
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: {
//方法1
async setWaterFallLayout() {
for (let item of this.imgList) {
let img = new Image();
img.src = item;
try{
let h = await this.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) {
return new Promise((resolve,reject) => {
//圖片加載完成
img.onload = () => {
let h = (img.height / img.width) * this.columnWidth;//計(jì)算圖片渲染后高度
resolve(h);
};
//加載出錯(cuò)
img.onerror=()=>{
reject('error')
}
});
},
},
};
</script>
2.方式2(父元素高度比較法)
每次放入圖片需要等待渲染后再重新計(jì)算父元素高度,關(guān)鍵代碼 await this.$nextTick()
<script>
export default {
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: {
//方法2
async setWaterFallLayout2() {
for (let item of this.imgList) {
if (this.$refs.left.clientHeight <= this.$refs.right.clientHeight) {//左邊列比右邊低,圖片放入左邊
this.leftList.push(item);
} else {//否則圖片放入右邊
this.rightList.push(item);
}
await this.$nextTick();//等待渲染完成后重新比較左右高度
}
},
},
};
</script>
三.uniapp實(shí)現(xiàn)
由于uniapp獲取元素高度和vue有所區(qū)別,造成實(shí)現(xiàn)瀑布流方式也需要調(diào)整。我們知道uniapp不能通過(guò)this.$ref.xx.clientHeight獲取元素高度,而需要通過(guò)uni.createSelectorQuery().in(this).select(‘.xxxx’).boundingClientRect().exec()來(lái)獲取,且經(jīng)過(guò)實(shí)測(cè)當(dāng)圖片動(dòng)態(tài)加入列后通過(guò)該api計(jì)算出父元素真實(shí)高度是不準(zhǔn)確的,所以u(píng)niapp瀑布流布局實(shí)現(xiàn)方式只能通過(guò)方法1(也即圖片高度累加法)進(jìn)行實(shí)現(xiàn),除了上面方法1通過(guò)img.onload來(lái)獲取圖片高度外,uniapp還提供uni.getImageInfo方法來(lái)更方便獲取圖片高度。
代碼實(shí)現(xiàn)
<template> <view class="page"> <view class="left" ref="left"> <image class="image" v-for="(item,i) in leftList" :key="i" :src="item" mode="widthFix"></image> </view> <view class="right" ref="right"> <image class="image" v-for="(item,i) in rightList" :key="i" :src="item" mode="widthFix"></image> </view> </view> </template>
<style lang="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>
export default {
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
//方法1
this.setWaterFallLayout()
//方法2
// this.setWaterFallLayout2()
}).exec()
})
},
methods: {
//方法1通過(guò)img.onload
async setWaterFallLayout() {
for (let item of this.imageList) {
let img = new Image()
img.src = item
try {
let h = await this.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) {
return new Promise((resolve, reject) => {
img.onload = () => {
let h = img.height / img.width * this.columnWidth
resolve(h)
}
//加載出錯(cuò)
img.onerror = () => {
reject('error')
}
})
},
//方法2通過(guò)uni.getImageInfo
async setWaterFallLayout2() {
for (let item of this.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>

四、多列實(shí)現(xiàn)
多列實(shí)現(xiàn)和2列一樣,動(dòng)態(tài)生成每列圖片數(shù)據(jù)和記錄每列高度

代碼實(shí)現(xiàn)
以最簡(jiǎn)單的父元素高度比較法(方式2)為例實(shí)現(xiàn),圖片高度累加比較法(方式1)自行類(lèi)比實(shí)現(xiàn)
<template>
<div class="page">
<div
class="column"
ref="column"
v-for="(item, index) in columnList"
:key="index"
>
<img class="img" v-for="(n, i) in item" :key="i" :src="n" />
</div>
</div>
</template>
<style scoped>
.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>
export default {
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() {
//初始化數(shù)據(jù)
for (let i = 0; i < this.columnCount; i++) {
this.columnList.push([]);//生成每列圖片數(shù)組
}
},
mounted() {
this.$nextTick(()=>{
this.setWaterFallLayout();
})
},
methods: {
//瀑布布局
async setWaterFallLayout() {
for (let item of this.imgList) {
let columnHeight = this.$refs.column.map((item) => item.clientHeight); //每列高度數(shù)組
let min = Math.min(...columnHeight); //找出最小高度值
let index = columnHeight.findIndex((item) => item === min); //找出最小高度列的索引
this.columnList[index].push(item);//放入圖片
await this.$nextTick(); //等待渲染完成后重新比較高度
}
},
},
};
</script>
總結(jié)
到此這篇關(guān)于vue+uniapp瀑布流布局多種實(shí)現(xiàn)方式的文章就介紹到這了,更多相關(guān)vue uniapp瀑布流布局實(shí)現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue2路由動(dòng)畫(huà)效果的實(shí)現(xiàn)代碼
本篇文章主要介紹了Vue2路由動(dòng)畫(huà)效果的實(shí)現(xiàn)代碼,可以根據(jù)不同的路徑去改變動(dòng)畫(huà)的效果,有興趣的可以了解一下2017-07-07
web項(xiàng)目開(kāi)發(fā)中2個(gè)Token原因解析及示例代碼
這篇文章主要介紹了web項(xiàng)目開(kāi)發(fā)中會(huì)出現(xiàn)2個(gè)Token原因的解析以及實(shí)現(xiàn)的示例代碼,有需要的同學(xué)可以借鑒參考下,希望可以有所幫助2021-09-09
vue使用路由守衛(wèi)實(shí)現(xiàn)菜單的權(quán)限設(shè)置
我們使?vue-element-admin前端框架開(kāi)發(fā)后臺(tái)管理系統(tǒng)時(shí),?般都會(huì)涉及到菜單的權(quán)限控制問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于vue使用路由守衛(wèi)實(shí)現(xiàn)菜單的權(quán)限設(shè)置的相關(guān)資料,需要的朋友可以參考下2023-06-06
Vue解析帶html標(biāo)簽的字符串為dom的實(shí)例
今天小編就為大家分享一篇Vue解析帶html標(biāo)簽的字符串為dom的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11
vue項(xiàng)目首次打開(kāi)時(shí)加載速度很慢的優(yōu)化過(guò)程
這篇文章主要介紹了vue項(xiàng)目首次打開(kāi)時(shí)加載速度很慢的優(yōu)化過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
vue3.0 CLI - 2.3 - 組件 home.vue 中學(xué)習(xí)指令和綁定
這篇文章主要介紹了vue3.0 CLI - 2.3 - 組件 home.vue 中學(xué)習(xí)指令和綁定的相關(guān)知識(shí),本文通過(guò)實(shí)例代碼相結(jié)合的形式給大家介紹的非常詳細(xì) ,需要的朋友可以參考下2018-09-09

