欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 新车 > 瀑布流布局

瀑布流布局

2024/11/30 10:46:20 来源:https://blog.csdn.net/2303_80137294/article/details/144010945  浏览:    关键词:瀑布流布局

瀑布流布局

实现思路

首先我们先介绍一下瀑布流布局实现的思路

  1. 控制容器内每一列卡片的宽度相同(不同图片尺寸等比例缩放)
  2. 第一行卡片紧挨着排列,第二行开始,每张卡片摆放到当前所有列中高度最小的一列下面

组件结构

首先展示一下整个DOM的结构

<template><div class="waterfall-container" ref="containerRef" @scroll="handleScroll"><div class="waterfall-list" ref="listRef"><divclass="waterfall-item"v-for="(item, index) in state.cardList":key="item.id":style="{width: `${state.cardWidth}px`,transform: `translate3d(${state.cardPos[index].x}px, ${state.cardPos[index].y}px, 0)`,}"><slotname="item":item="item":index="index":imageHeight="state.cardPos[index].imageHeight"></slot></div></div></div>
</template>

主要的结构就是waterfall-container,waterfall-list,waterfall-item

container 作为整个瀑布流的容器,在它上面展示滚动条, list 作为 item 的容器可以开启相对定位,而 item 开启绝对定位,通过 translate 来控制每张卡片的位置实现最后的布局,所以每张卡片定位统一放到左上角即可

<style scoped>
.waterfall-container {width: 100%;height: 100vh;overflow-y: scroll;overflow-x: hidden;
}
.waterfall-list {width: 100%;position: relative;
}
.waterfall-item {position: absolute;left: 0;top: 0;box-sizing: border-box;transition: all 0.2s;
}
</style>

对于这里用到的数据如下:

const props = defineProps({
//用于拿到数据request: {type: Function,required: true // 确保父组件必须提供一个函数},//列信息column: {type: Number,default: 4},//间距gap: {type: Number,default: 10},//页码,通过这个来获取信息pageSize: {type: Number,default: 20},//触底加载新数据bottom: {type: Number,default: 20}
})
const state = ref({isFinish: false,loading: false,page: 1, //数据的页码cardWidth: 0, //卡片的宽度cardList: [], //数据源cardPos: [], //卡片的位置信息columnHeight: new Array(props.column).fill(0), //列高度信息preLen: 0
})

函数封装

接下来就是进行计算每张卡片的具体位置,为最后的布局做准备

//计算出高度最小的那一列的索引和高度
const minColumn = computed(() => {let minIndex = -1,minHeight = Infinitystate.value.columnHeight.forEach((item, index) => {if (item < minHeight) {minHeight = itemminIndex = index}})return {minIndex,minHeight}
})

这里通过遍历存储每列高度信息的数组,返回高度最小的那一列的索引和高度

//根据页码得到数据
const getCardList = async (page, pageSize) => {if (state.value.isFinish) {return}state.value.loading = trueconst list = await props.request(page, pageSize)state.value.page++if (!list.length) {state.value.isFinish = truereturn}state.value.cardList = [...state.value.cardList, ...list]computedCardPos(list)state.value.loading = false
}

封装获取数据的函数,通过页码来获得新数据

//计算卡片的图片的高度
const computedImageHeight = list => {list.forEach(item => {const imageHeight = Math.floor((item.height * state.value.cardWidth) / item.width)state.value.cardPos.push({width: state.value.cardWidth,imageHeight: imageHeight,cardHeight: 0,x: 0,y: 0})})
}

这里通过给定的图片宽高信息,和每一列的宽度,进而计算出每张图片缩放之后的高度

//根据真实dom计算出卡片的具体位置
const computedRealDomPos = list => {const children = listRef.value.childrenlist.forEach((item, index) => {const nextIndex = state.value.preLen + indexconst cardHeight = children[nextIndex].getBoundingClientRect().heightif (index < props.column && state.value.cardList.length <= props.pageSize) {state.value.cardPos[nextIndex] = {...state.value.cardPos[nextIndex],cardHeight: cardHeight,x:nextIndex % props.column !== 0? nextIndex * (state.value.cardWidth + props.gap): 0,y: 0}state.value.columnHeight[nextIndex] = cardHeight + props.gap} else {const { minIndex, minHeight } = minColumn.valuestate.value.cardPos[nextIndex] = {...state.value.cardPos[nextIndex],cardHeight: cardHeight,x: minIndex ? minIndex * (state.value.cardWidth + props.gap) : 0,y: minHeight}state.value.columnHeight[minIndex] += cardHeight + props.gap}})state.value.preLen = state.value.cardPos.length
}

这个函数则是要计算每张卡片的具体偏移量,做法是对于传入的数据数组,利用记录列高度数据的数组,计算每张卡片的水平和垂直偏移量,再存入数组中

//计算每个卡片的位置
const computedCardPos = async list => {computedImageHeight(list)await nextTick()computedRealDomPos(list)
}

计算每个卡片的位置

//初始化,根据列数计算每列卡片的宽度
const init = () => {if (containerRef.value) {const containerWidth = containerRef.value.clientWidthstate.value.cardWidth =(containerWidth - props.gap * (props.column - 1)) / props.columngetCardList(state.value.page, props.pageSize)resizeObserver.observe(containerRef.value)}
}onMounted(() => {init()
})

初始化函数

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com