一种是使用纯 JavaScript 来实现,另一种是使用第三方库 Masonry.js
方案一:使用纯 JavaScript 实现
这种方法适用于想要完全控制瀑布流布局的情况。
步骤 1:HTML 结构
首先,在 HTML 中定义一个容器来存放瀑布流中的元素。
html
<div id="waterfall">
<!-- 瀑布流中的元素将动态插入到这里 -->
</div>
步骤 2:Vue 组件
接下来,创建一个 Vue 组件来处理瀑布流逻辑。
html
<template>
<div id="waterfall" ref="waterfall">
<div v-for="(item, index) in items" :key="index" class="item" :style="{height: item.height + 'px'}">
<img :src="item.src" :alt="item.alt" @load="onImgLoad(index)">
</div>
</div>
</template>
<script>
export default {
data() {
return {
items: [
// 示例数据
{ src: 'image1.jpg', height: 200, alt: 'image1' },
{ src: 'image2.jpg', height: 300, alt: 'image2' },
// 更多数据...
],
columns: []
};
},
methods: {
onImgLoad(index) {
const item = this.items[index];
const shortestColumn = this.columns.reduce((minCol, currentCol) =>
currentCol.height < minCol.height ? currentCol : minCol, this.columns[0]);
shortestColumn.height += item.height;
shortestColumn.items.push(item);
this.reorderColumns();
},
reorderColumns() {
this.columns.sort((a, b) => a.height - b.height);
},
init() {
const waterfall = this.$refs.waterfall;
this.columns = [];
this.items.forEach((item, index) => {
const column = this.columns.length > 0 ? this.columns[0] : { height: 0, items: [] };
const div = document.createElement('div');
div.className = 'column';
const img = document.createElement('img');
img.src = item.src;
img.alt = item.alt;
img.onload = () => {
item.height = img.offsetHeight;
column.height += img.offsetHeight;
column.items.push(item);
this.reorderColumns();
this.$forceUpdate(); // 强制更新视图
};
div.appendChild(img);
waterfall.appendChild(div);
});
}
},
mounted() {
this.init();
}
}
</script>
<style scoped>
#waterfall {
column-count: 3; /* 初始列数 */
column-gap: 10px;
margin: 0 auto;
max-width: 900px;
}
.item {
break-inside: avoid;
page-break-inside: avoid;
overflow: hidden;
}
</style>
方案二:使用 Masonry.js
如果你希望使用一个成熟的库来简化瀑布流的实现,可以选择 Masonry.js。
步骤 1:安装 Masonry.js
首先,你需要安装 Masonry.js:
vbscript
npm install masonry-layout
步骤 2:引入 Masonry.js
然后,在你的 Vue 组件中引入 Masonry.js。
html
<template>
<div id="masonry" class="masonry">
<div v-for="item in items" :key="item.id" class="item">
<img :src="item.src" :alt="item.alt">
</div>
</div>
</template>
<script>
import Masonry from 'masonry-layout';
export default {
data() {
return {
items: [
// 示例数据
{ id: 1, src: 'image1.jpg', alt: 'image1' },
{ id: 2, src: 'image2.jpg', alt: 'image2' },
// 更多数据...
]
};
},
mounted() {
this.initMasonry();
},
methods: {
initMasonry() {
this.msnry = new Masonry('#masonry', {
itemSelector: '.item',
columnWidth: '.item'
});
this.items.forEach(item => {
this.$nextTick(() => {
this.msnry.appended(document.querySelector(`[data-id="${item.id}"]`));
this.msnry.layout();
});
});
}
}
}
</script>
<style scoped>
.masonry {
column-count: 3; /* 初始列数 */
column-gap: 10px;
margin: 0 auto;
max-width: 900px;
}
.item {
break-inside: avoid;
page-break-inside: avoid;
overflow: hidden;
}
</style>