布局特点
- 代码简单,完整代码仅仅75行
- 图片完整展示,不会被裁切,等比缩放,而非拉伸
- 以图片异步加载结束时间的顺序渲染图片,防止页面过大闪动
- 最后一行图片过少时,图片正常显示,不会缩放占满整行
tips: github 图片加载较慢正好可以观察图片加载渲染过程
在线预览(github) https://haolang.github.io/web/demo/500px/
在线预览(gitee) http://haolang.gitee.io/web/demo/500px/
效果如下
代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>完美flex横向瀑布流布局</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
.primary {
display: flex;
flex-wrap: wrap;
}
/*占位元素,最后一行图片过少时,图片不缩放*/
.primary::after {
content: '';
flex-grow: 999999999;
min-width: 200px; /* 图片可以占满一行时保证换行,否则最后一行末尾可能会出现一小段空白 */
height: 0;
}
.image-box {
margin: 5px;
display: block;
}
.image-box img {
display: block;
width: 100%;
}
</style>
</head>
<body>
<div id="app" class="primary">
<div
v-for="(image,key) in images"
:key="key"
class="image-box"
:style="{
width: `${image.width * 200 / image.height}px`,
flexGrow: image.width / image.height * 1000
}"
>
<img :src="image.src" alt="">
</div>
</div>
</body>
<script>
new Vue({
el: '#app',
data() {
return {
imagesBaseUrl: './images',
images: []
}
},
methods: {
getImage(imageSrc) {
let img = new Image();
img.src = imageSrc;
//获取图片尺寸
img.onload = () => {
this.images.push({
src: img.src,
width: img.width,
height: img.height
});
}
}
},
mounted() {
for (let i = 0; i < 28; i++) {
const imageSrc = `${this.imagesBaseUrl}/i${i}.jpg`;
this.getImage(imageSrc);
}
}
})
</script>
</html>
图片容器 image-box style 解释
-
width:
${image.width * 200 / image.height}px
保证图片高度以200px为基准 -
flexGrow: image.width/image.height * 1000 这行代码(image.width / image.height )部分可以理解为 (image.width/image.height) / (image.height/image.height)
即图片的高宽同时除以高度,图片高度均为1时,图片宽度即为整行所占比,即flex-grow的值,
结果乘以1000 防止 flex-grow 的值小于1,因为当浏览器窗口很窄时,出现只能一张图片单独占据一行的情况,若 flex-grow 的值小于1会导致图片收缩不能占满一行。
其他方案
1. 加载图片显示顺序始终一致,页面无大幅闪动
本例可以容易的修改图片为同步加载,但得不偿失,图片一张加载完毕再加载下一张,加载速度会变慢
2. 加载图片显示顺序始终一致,且不影响图片加载速度
想要保证图片顺序一致,this.imageArraySize.push 修改为通过索引 this.imageArraySize[i] 添加数据即可但是由于图片不断插入导致回流与重构,会导致页面在图片加载完毕之前不断闪动。
参考链接中的方案使用后台图片尺寸数据占位,防止页面闪动