vue3实现瀑布流布局组件

news/发布时间2024/5/14 16:28:20

先看效果图
在这里插入图片描述

直接上代码
utils.js

// 用于模拟接口请求
export const getRemoteData = (data = '获取数据', time = 2000) => {return new Promise((resolve) => {setTimeout(() => {console.log(`模拟获取接口数据`, data)resolve(data)}, time)})
}// 获取数组随机项
export const getRandomElement = (arr) => {var randomIndex = Math.floor(Math.random() * arr.length);return arr[randomIndex];
}// 指定范围随机数
export const getRandomNumber = (min, max) => {return Math.floor(Math.random() * (max - min + 1) + min);
}// 节流
export const throttle = (fn, time) => {let timer = nullreturn (...args) => {if (!timer) {timer = setTimeout(() => {timer = nullfn.apply(this, args)}, time)}}
}
// 防抖
export const debounce = (fn, time) => {let timer = nullreturn (...args) => {clearTimeout(timer)timer = setTimeout(() => {fn.apply(this, args)}, time)}
}

data.js 模拟后台返回的数据

import { getRandomElement, getRandomNumber } from "./utils.js"const colorList = ['red', 'blue', 'green', 'pink', 'yellow', 'orange', 'purple', 'brown', 'gray', 'skyblue']export const createList = (pageSize) => {let list = Array.from({ length: pageSize }, (v, i) => i)return list.map(x => {return {background: getRandomElement(colorList),width: getRandomNumber(200, 600),height: getRandomNumber(400, 700),x: 0,y: 0}})
}

瀑布流布局组件waterfall.vue

<template><div class="waterfall-container" ref="containerRef" @scroll="handleScroll"><div class="waterfall-list"><divclass="waterfall-item"v-for="(item, index) in resultList":key="index":style="{width: `${item.width}px`,height: `${item.height}px`,transform: `translate3d(${item.x}px, ${item.y}px, 0)`,}"><slot name="item" v-bind="item"></slot></div></div></div>
</template>
<script setup>
import { ref, onMounted, computed, nextTick, onUnmounted } from "vue";
import { createList } from "@/common/data.js";
import { getRemoteData, throttle, debounce } from "@/common/utils.js";
const props = defineProps({// 间距gap: {type: Number,default: 10,},// 列数columns: {type: Number,default: 3,},// 距离底部bottom: {type: Number,default: 0,},// 分页大小pageSize: {type: Number,default: 10,},
});// 容器ref
const containerRef = ref(null);// 卡片宽度
const cardWidth = ref(0);// 列高度
const columnHeight = ref(new Array(props.columns).fill(0));// 数据list
const resultList = ref([]);// 当前页码
const pageNum = ref(1);// 加载状态
const loading = ref(false);// 计算最小列高度及其下标
const minColumn = computed(() => {let minIndex = -1,minHeight = Infinity;columnHeight.value.forEach((item, index) => {if (item < minHeight) {minHeight = item;minIndex = index;}});return {minIndex,minHeight,};
});// 获取接口数据
const getData = async () => {loading.value = true;const list = createList(props.pageSize);const resList = await getRemoteData(list, 300).finally(() => (loading.value = false));pageNum.value++;resultList.value = [...resultList.value, ...getList(resList)];
};// 滚动到底部获取新一页数据-节流
const handleScroll = throttle(() => {const { scrollTop, clientHeight, scrollHeight } = containerRef.value;const bottom = scrollHeight - clientHeight - scrollTop;if (bottom <= props.bottom) {!loading.value && getData();}
});// 拼装数据结构
const getList = (list) => {return list.map((x, index) => {const cardHeight = Math.floor((x.height * cardWidth.value) / x.width);const { minIndex, minHeight } = minColumn.value;const isInit = index < props.columns && resultList.length <= props.pageSize;if (isInit) {columnHeight.value[index] = cardHeight + props.gap;} else {columnHeight.value[minIndex] += cardHeight + props.gap;}return {width: cardWidth.value,height: cardHeight,x: isInit? index % props.columns !== 0? index * (cardWidth.value + props.gap): 0: minIndex % props.columns !== 0? minIndex * (cardWidth.value + props.gap): 0,y: isInit ? 0 : minHeight,background: x.background,};});
};// 监听元素
const resizeObserver = new ResizeObserver(() => {handleResize();
});// 重置计算宽度以及位置
const handleResize = debounce(() => {const containerWidth = containerRef.value.clientWidth;cardWidth.value =(containerWidth - props.gap * (props.columns - 1)) / props.columns;columnHeight.value = new Array(props.columns).fill(0);resultList.value = getList(resultList.value);
});const init = () => {if (containerRef.value) {const containerWidth = containerRef.value.clientWidth;cardWidth.value =(containerWidth - props.gap * (props.columns - 1)) / props.columns;getData();resizeObserver.observe(containerRef.value);}
};onMounted(() => {init();
});
// 取消监听
onUnmounted(() => {containerRef.value && resizeObserver.unobserve(containerRef.value);
});
</script><style lang="scss">
.waterfall {&-container {width: 100%;height: 100%;overflow-y: scroll;overflow-x: hidden;}&-list {width: 100%;position: relative;}&-item {position: absolute;left: 0;top: 0;box-sizing: border-box;transition: all 0.3s;}
}
</style>

使用该组件(这里columns写死了3列)

<template><div class="container"><WaterFall :columns="3" :gap="10"><template #item="{ background }"><div class="card-box" :style="{ background }"></div></template></WaterFall></div>
</template><script setup>
import WaterFall from "@/components/waterfall.vue";
</script><style scoped lang="scss">
.container {width: 700px;  /* 一般业务场景不是固定宽度 */height: 800px;border: 2px solid #000;margin-top: 10px;margin-left: auto;
}
.card-box {position: relative;width: 100%;height: 100%;border-radius: 4px;
}
</style>

若要响应式调整列数,可参考以下代码


const fContainerRef = ref(null);
const columns = ref(3);
const fContainerObserver = new ResizeObserver((entries) => {changeColumn(entries[0].target.clientWidth);
});// 根据宽度,改变columns列数
const changeColumn = (width) => {if (width > 1200) {columns.value = 5;} else if (width >= 768 && width < 1200) {columns.value = 4;} else if (width >= 520 && width < 768) {columns.value = 3;} else {columns.value = 2;}
};onMounted(() => {fContainerRef.value && fContainerObserver.observe(fContainerRef.value);
});onUnmounted(() => {fContainerRef.value && fContainerObserver.unobserve(fContainerRef.value);
});

瀑布流布局组件监听columns变化

watch(() => props.columns,() => {handleResize();}
);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.bcls.cn/qPBk/856.shtml

如若内容造成侵权/违法违规/事实不符,请联系编程老四网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

08MARL深度强化学习 independent learning

文章目录 前言1、Independent Value-based Learning2、Independent Policy Gradient Methods 前言 记录independent learning算法的基础概念&#xff0c;使用一些RL算法训练多智能体 1、Independent Value-based Learning 基于值的独立学习算法&#xff1a;每个智能体根据自身…

jsp课程教学管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 课程教学管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0…

第13章 网络 Page741~744 asio核心类 ip::tcp::socket

1. ip::tcp::socket liburl库使用"curl*" 代表socket 句柄 asio库使用ip::tcp::socket类代表TCP协议下的socket对象。 将“句柄”换成“对象”,因为asio库是不打折扣的C库 ip::tcp::socket提供一下常用异步操作都以async开头 表13-3 tcp::socket提供的异步操作 …

docker本地目录挂载

小命令 1、查看容器详情 docker inspect 容器名称 还是以nginx为例&#xff0c;上篇文章我们制作了nginx静态目录的数据卷&#xff0c;此时查看nginx容器时会展示出来&#xff08;docker inspect nginx 展示信息太多&#xff0c;这里只截图数据卷挂载信息&#xff09;&#…

FOC电流环速度环调试记录

FOC电流环速度环调试记录 电流环&#xff1a; 首先foc控制中都采用PI控制&#xff0c;没有引入微分&#xff0c;因为电流的采样率非常高不需要加入微分项&#xff1b;微分项的加入&#xff0c;会使电流采样中的高频小信号误差起到放大的作用&#xff0c;把小的误差放大&#…

C语言与C++:探索两种强大的编程语言

在编程的世界里&#xff0c;C语言和C无疑是两座重要的里程碑。它们不仅各自拥有独特的特点和优势&#xff0c;而且还在不同的领域和场景中发挥着关键作用。本文将深入探讨C语言和C的相似之处与差异&#xff0c;帮助读者更好地理解和应用这两种编程语言。 一、C语言&#xff1a…

【Linux】---Linux下基本指令(2)

目录 一、指令详细介绍1.1 cat 指令1.2 echo 指令1.3 more 指令1.4 less 指令1.5 head 指令1.6 tail 指令1.7 date 指令1.8 cal 指令1.9 find 指令1.10 grep 指令1.11 zip/unzip 指令1.12 tar 指令1.13 uname –r 指令&#xff1a; 一、指令详细介绍 1.1 cat 指令 语法&#…

论文阅读-PIM-tree:一种面向内存处理的抗偏移索引

论文名称&#xff1a;PIM-tree: A Skew-resistant Index for Processing-in-Memory 摘要 当今的内存索引性能受到内存延迟/带宽瓶颈的限制。Processing-in-memory (PIM) 是一种新兴的方法&#xff0c;可能通过实现低延迟内存访问&#xff0c;其聚合内存带宽随 PIM 节点数量扩…

IMX6ULL移植U-Boot 2022.04

目录 目录 1.编译环境以及uboot版本 2.默认编译测试 3.uboot中新增自己的开发板 3.编译测试 4.烧录测试 5.patch文件 1.编译环境以及uboot版本 宿主机Debian12u-boot版本lf_v2022.04 ; git 连接GitHub - nxp-imx/uboot-imx: i.MX U-Boot交叉编译工具gcc-arm-10.3-2021.0…

为什么从没有负值的数据中绘制的小提琴图(Violin Plot)会出现负值部分?

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 小提琴图&#xff08;Violin Plot&#xff09; 是一种用于展示和比较数据分布的可视化工具。它结合了箱形图&#xff08;Box Plot&#xff09;和密度图&#xff08;Kernel Density Plot&#xff09;的特…

centos7 arm服务器编译安装onnxruntime-gpu

前言 ONNX Runtime是适用于Linux,Windows和Mac上ONNX格式的机器学习模型的高性能推理引擎,但在arm服务器上,onnxruntime只有CPU版的,GPU版的没有,因此需要自行去编译GPU版本的才可以。 环境准备 1、python3.8 2、cmake:2.26.0版本以上,可以直接下载aarch64版本的进行…

【JavaEE】_多线程Thread类及其常用方法

目录 1. Thread类常用构造方法 2. Thread类的几个常见属性 3. 启动一个线程 4. 中断一个线程 4.1 方法1&#xff1a;手动设置标志位 4.2 方法2&#xff1a;使用Thread内置的标志位 5. 等待一个线程 6. 获取当前线程引用 7. 休眠当前线程 1. Thread类常用构造方法 方法…

MATLAB | 情人节画个花瓣venn图?

之前七夕节情人节各种花&#xff0c;相册&#xff0c;爱心啥的都快画够了&#xff0c;今年画个花瓣韦恩图&#xff1f; 花瓣上的数字是仅属于该类的样本数&#xff0c;而中心的数字是属于每一类的样本数 教程部分 0 数据准备 % 给组起名t1 t2 t3...t15 setName compose(t%d,…

视频接入协议之MIPI

MIPI&#xff08;Mobile Industry Processor Interface&#xff09;是一种用于移动设备的串行接口标准&#xff0c;旨在提供高速、低功耗、低成本的接口解决方案。MIPI联盟是一个全球性的组织&#xff0c;致力于开发、推广和管理MIPI标准。 MIPI接口包括了多种协议和规范&…

qwen1.5 chat vllm推理使用案例

参考:https://github.com/QwenLM/Qwen1.5 下载:https://huggingface.co/collections/Qwen/qwen15-65c0a2f577b1ecb76d786524 下载可以参考huggingface-cli 命令下载使用:https://blog.csdn.net/weixin_42357472/article/details/1326636931、vllm运行 显卡驱动:NVIDIA-S…

MySQL 基础知识(十)之 MySQL 架构

目录 1 MySQL 架构说明 2 连接层 3 核心业务层 3.1 查询缓存 3.2 解析器 3.3 优化器 3.4 执行器 4 存储引擎层 5 参考文档 1 MySQL 架构说明 下图是 MySQL 5.7 及其之前版本的逻辑架构示意图 MySQL 架构大致可分为以下三层&#xff1a; 连接层&#xff1a;负责跟客户…

【开源】在线办公系统 JAVA+Vue.js+SpringBoot+MySQL

目录 1 功能模块1.1 员工管理模块1.2 邮件管理模块1.3 人事档案模块1.4 公告管理模块 2 系统展示3 核心代码3.1 查询用户3.2 导入用户3.3 新增公告 4 免责声明 本文项目编号&#xff1a; T 001 。 \color{red}{本文项目编号&#xff1a;T001。} 本文项目编号&#xff1a;T001。…

HAL STM32通过multi_button库处理按键事件

HAL STM32通过multi_button库处理按键事件 &#x1f4cd;作者&#xff1a;0x1abin的multi_button库:https://github.com/0x1abin/MultiButton &#x1f4d8;MultiButton简介 MultiButton 是一个小巧简单易用的事件驱动型按键驱动模块&#xff0c;可无限量扩展按键&#xff0c;…

SQL-Labs靶场“1-5”关通关教程

君衍. 一、准备工作二、第一关 基于GET单引号字符型注入1、源码分析2、联合查询注入过程 三、第二关 基于GET整型注入1、源码分析2、联合查询注入过程 四、第三关 基于GET单引号变形注入1、源码分析2、联合查询注入过程 五、第四关 基于GET双引号字符型注入1、源码分析2、联合查…

【RHCE】shell条件测试练习

目录 1、判断当前磁盘剩余空间是否有20G&#xff0c;如果小于20G&#xff0c;则将报警邮件发送给管理员&#xff0c;每天检查次磁盘剩余空间。 2、判断web服务是否运行 3、使用curl命令访问第二题的web服务&#xff0c;看能否正常访问&#xff0c;如果能正常访问&#xff0c;…
推荐文章