购物网站要多少钱,专业的新乡网站建设,wordpress 微博图床,一级造价工程师吧思路 1.首先定义一个瀑布流容器#xff0c;它的高度暂定#xff08;后面会更新#xff09;。把需要布局的组件#xff08;这里叫做waterfall-item#xff09;放在瀑布流容器里面渲染出来。使用绝对定位#xff08;position: absolute#xff09;#xff0c;把它移到屏幕…思路 1.首先定义一个瀑布流容器它的高度暂定后面会更新。把需要布局的组件这里叫做waterfall-item放在瀑布流容器里面渲染出来。使用绝对定位position: absolute把它移到屏幕外面不要占用页面高度并且设置不可见visibility:hidden。
div classwaterfall-container refwaterfallWrapper :style{ height: wrapperHeight px }divv-for(post, index) in posts:keypost.titleclasswaterfall-itemdiv classwaterfall-cardPostCard:titlepost.title:contentpost.excerpt:timenew Date(post.date).toLocaleDateString():tagpost.tags ? post.tags.join(, ) : 未分类:imgpost.img:path/post/${post.file}:idpost.titleimageLoadedonImageLoaded//div/div/div.waterfall-item {position: absolute;left: 0;top: 0;transform: translate3d(0, 3000px, 0);visibility: hidden;/* 让容器不被空白占位的 trick */
}2.渲染出来之后才能计算高度。获取.waterfall-item的dom元素遍历这些元素使用getBoundingClientRect()获取高度。
3.开始布局。以2列为例新建两个变量分别表示2列的高度。遍历第2步获取的dom元素的高度把dom元素的高度加到最小的高度上。这个过程还可以考虑在组件之间加上留白gutter。
4.使用transform样式将waterfall-item移动到对应高度所在的位置。transform将组件移动到指定坐标横坐标跟列有关纵坐标跟高度有关。
5.更新瀑布流容器的高度为两列高度中最大者。
// 瀑布流容器引用
const waterfallWrapper refHTMLElement | null(null);
// 瀑布流容器高度
const wrapperHeight ref(0);// 一些瀑布流配置属性
const gutter 20; // 卡片之间的间距单位px
const cols ref(2); // 列数可根据响应式需求调整
const colWidth ref(0); // 每列宽度或你可以动态计算
const hasAroundGutter ref(true);
const animationCancel ref(false); // 是否取消动画
const posDuration ref(300); // 位置动画时长 (ms)/** 2、3、4、5步的布局函数 */
const layoutHandle async (): Promiseboolean {return new Promise((resolve) {// 初始化 posYinitY();// 获取 .waterfall-item DOM 列表const items: HTMLElement[] [];if (waterfallWrapper.value) {waterfallWrapper.value.childNodes.forEach((el: any) {if (el.className waterfall-item) items.push(el);});}if (!items.length) return false;// 遍历每个卡片for (let i 0; i items.length; i) {const curItem items[i] as HTMLElement;const style curItem.style;// 最小列const minY Math.min(...posY.value);const minYIndex posY.value.indexOf(minY);// 计算 Xconst curX getX(minYIndex);// 设置 transformstyle.transform translate3d(${Math.floor(curX)}px, ${Math.floor(minY)}px, 0);style.width ${colWidth.value}px;style.visibility visible;// 测量高度const { height } curItem.getBoundingClientRect();// 输出卡片标题和高度// console.log(Card ${i} height: ${height});// 更新列高posY.value[minYIndex] height;// 入场动画可选if (!animationCancel.value) {addAnimation(curItem, () {const time posDuration.value / 1000;style.transition transform ${time}s;});}}// 容器高度 最长列wrapperHeight.value Math.max(...posY.value);// 等待动画结束setTimeout(() {resolve(true);}, posDuration.value);});
};/** 初始化 posY */
const initY () {posY.value new Array(cols.value).fill(hasAroundGutter.value ? gutter : 0);
};/** 计算给定列的 X 坐标 */
const getX (index: number): number {const count hasAroundGutter.value ? index 1 : index;return gutter * count colWidth.value * index;
};/** 简单的动画函数给卡片添加class或行内属性 */
function addAnimation(item: HTMLElement, callback?: () void) {// 也可以从 item.firstChild 取到实际卡片 DOM// 并添加动画class// 这里为简单演示const content item.firstChild as HTMLElement;if (content) {// 添加一系列动画class/属性content.classList.add(animate__animated, animate__fadeIn); // etc.// 回调if (callback) {setTimeout(() {callback();}, 300); // 300ms or 你自己的计算}}
}细节
实际场景中图片一般使用懒加载这会导致在组件计算高度时因为图片还没有被加载出来所以得到错误的高度。这时候就需要在组件里添加一个onImageLoaded函数当图片加载完成后调用重新布局。
// 图片加载完成后再次布局可加防抖
let timer: number | null null;
function onImageLoaded() {if (timer) clearTimeout(timer);timer setTimeout(() {layoutHandle(); // 重新布局}, 100); // 防抖 100ms
}屏幕尺寸变化时重新布局。设置两个监听器监听屏幕尺寸变化当屏幕尺寸改变了之后一个触发宽度重新设置第二个触发重新布局。
// 定义函数: colWidth containerWidth - 3 * gutter
function updateColWidth() {const container waterfallWrapper.value;if (!container) return;// 父容器的实际宽度const containerWidth container.clientWidth;// 计算后赋值colWidth.value (containerWidth - 3 * gutter)/2;console.log(containerWidth:, containerWidth);console.log(colWidth:, colWidth.value);
}onMounted(() {updateColWidth();window.addEventListener(resize, updateColWidth);window.addEventListener(resize, layoutHandle);
});防抖意思就是防止频繁触发布局造成性能爆炸。这个问题可能会在图片非常多或者屏幕宽度频繁变化时出现。解决思路很简单就是在所有布局操作前加个定时器使得在规定时间内只能触发有限次数。代码在细节1有体现。
代码参考https://github.com/heikaimu/vue3-waterfall-plugin
感谢作者开源。