一个函数最快解决瀑布流布局实现

148 阅读1分钟
import { pxToVw } from './num'

/**
 * 瀑布布局
 * @param parent 父盒子
 * @param colNum 多少列
 * @param wgap 宽度间隔 单位是vw
 * @param hgap 高度间隔 单位是vw
 * @returns 返回父盒子的高度 绝对定位会导致高度塌陷
 */
export const waterFall = (
	parent: Element | HTMLDivElement,
	colNum: number,
	wgap: number,
	hgap: number
) => {
	// 所有card的div
	const childrenElements = parent.children as unknown as HTMLDivElement[]
	// 初始化每一行的高度 用于布局时的top,默认为0
	const childrenHeightArr = Array.from<number>({ length: colNum }).fill(0)
	// card的宽度
	const cardWidth = pxToVw(childrenElements[0].offsetWidth)

	for (const child of childrenElements) {
		// 拿到最小高度 以及 对应的index
		const minHeight = Math.min.apply(null, childrenHeightArr)
		const minIndex = childrenHeightArr.indexOf(minHeight)

		// 设置当前card位置,整体逻辑为不断的向高度最小的位置插入card,类似于俄罗斯方块
		child.style.position = 'absolute' // style设置样式
		child.style.top = `${minHeight}vw`
		child.style.left = `${cardWidth * minIndex + (minIndex ? wgap : 0)}vw`

		// 不断更新记录的高度
		childrenHeightArr[minIndex] += pxToVw(child.offsetHeight) + hgap
	}

	return {
		parentHeight: Math.max.apply(null, childrenHeightArr)
	}
}

瀑布流大部分都是定宽的 所以列数可以预知. 我的适配用的vw,rem的适配切换下单位转换函数即可.没有适配直接删除pxToVw的使用.