78 lines
1.4 KiB
Vue
78 lines
1.4 KiB
Vue
|
<template>
|
|||
|
<div class="waterfall-container" ref="container">
|
|||
|
<div
|
|||
|
v-for="(column, columnIndex) in columns"
|
|||
|
:key="columnIndex"
|
|||
|
class="waterfall-column"
|
|||
|
:style="{ width: `${100 / columnCount}%` }"
|
|||
|
>
|
|||
|
<div
|
|||
|
v-for="item in column"
|
|||
|
:key="item.id"
|
|||
|
class="waterfall-item"
|
|||
|
>
|
|||
|
<!-- 默认插槽,传入当前item数据 -->
|
|||
|
<slot :item="item">
|
|||
|
</slot>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</template>
|
|||
|
|
|||
|
<script setup>
|
|||
|
import { ref, onMounted, watch } from 'vue'
|
|||
|
|
|||
|
const props = defineProps({
|
|||
|
items: {
|
|||
|
type: Array,
|
|||
|
required: true
|
|||
|
},
|
|||
|
columnCount: {
|
|||
|
type: Number,
|
|||
|
default: 2
|
|||
|
}
|
|||
|
})
|
|||
|
|
|||
|
const columns = ref([])
|
|||
|
|
|||
|
// 计算每列的内容
|
|||
|
const calculateColumns = () => {
|
|||
|
const cols = Array.from({ length: props.columnCount }, () => [])
|
|||
|
props.items.forEach((item, index) => {
|
|||
|
// 将项目添加到高度最小的列中
|
|||
|
const columnIndex = index % props.columnCount
|
|||
|
cols[columnIndex].push(item)
|
|||
|
})
|
|||
|
|
|||
|
columns.value = cols
|
|||
|
}
|
|||
|
|
|||
|
// 监听items变化重新计算列
|
|||
|
watch(() => props.items, () => {
|
|||
|
calculateColumns()
|
|||
|
}, { deep: true })
|
|||
|
|
|||
|
onMounted(() => {
|
|||
|
calculateColumns()
|
|||
|
})
|
|||
|
</script>
|
|||
|
|
|||
|
<style scoped>
|
|||
|
.waterfall-container {
|
|||
|
display: flex;
|
|||
|
width: 100%;
|
|||
|
gap: 16px;
|
|||
|
}
|
|||
|
|
|||
|
.waterfall-column {
|
|||
|
display: flex;
|
|||
|
flex-direction: column;
|
|||
|
gap: 16px;
|
|||
|
}
|
|||
|
|
|||
|
.waterfall-item {
|
|||
|
break-inside: avoid;
|
|||
|
}
|
|||
|
|
|||
|
/* 默认样式可以移到使用组件时自定义 */
|
|||
|
</style>
|