vue3瀑布流示例,左侧菜单根据窗口滚动条进行固定和取消固定,实现瀑布流demo

news2024/9/22 7:38:59

瀑布流demo的实现效果:

效果说明:

1.使用vue3实现瀑布流效果;

2.瀑布流横向设置5等分,可根据个人需求调整;

3.左侧菜单可根据右侧滚动条滑动时进行固定和取消固定,实现更优的展示效果;

4.瀑布流中的图片可使用img标签,也可使用背景图片(代码中注释的部分已标名)

实现方式:

一、创建瀑布流子组件

1.新建瀑布流组件的vue文件,如命名为WaterFall.vue

2.构建瀑布流中展示的内容,可根据不同需求进行自定义

<template>
	<div class="list">
		<div
			class="item"
			v-for="(item, index) in waterList"
			:key="index"
			:style="{
				width: width + 'px',
				height: item.height + 'px',
				left: item.left + 'px',
				top: item.top + 'px',
				// 'background-image': 'url(' + item.image + ')', // 假设 item 对象中有 image 属性
				// 'background-size': 'cover', // 如果需要的话,设置背景图片大小
				// 'background-position': 'center', // 如果需要的话,设置背景图片位置
				// 'background-repeat': 'no-repeat', // 禁止背景图片重复
			}"
		>
			<img :src="item.image" :alt="item.text" />
			<p class="text-box">{{ item.text }}</p>
		</div>
	</div>
</template>

3.构建瀑布流展示的相关方法

这里需要说明的是:为增加该瀑布流的可复用性,瀑布流数据通过父组件的list进行传递,boxWidth是指盛放瀑布流的盒子宽度,也是通过父组件进行传递,也可个人自己定义。父组件在下面也会给出详细代码。

这里将每个瀑布流里面的盒子设置的间距为右边20,下边20,第一行的数据进行了特殊处理,可根据个人需求调整。

<script setup>
import { ref, reactive, onMounted } from 'vue';
const props = defineProps({
	list: {
		type: Array,
		default: () => {
			return [];
		},
	},
	boxWidth: {
		type: String,
		default: () => {
			return '';
		},
	},
});

const width = 226; // 图片宽度
const gap = 20; // 图片上下间距
const rightGap = 20; // 图片右间距
const waterList = ref([]); // 瀑布流数组
const heightList = reactive([]); // 列高度数组

// 屏幕宽度需要在 mounted 之后拿到
onBeforeUpdate(() => {
	// 计算列数
	console.log('组件里获取的宽度', props.boxWidth);
	const column = Math.floor(props.boxWidth / width); // 根据盒子的宽度确定列数
	console.log('计算的列数', column);
	// 核心内容就是维护每个图片的 left、top
	for (let i = 0; i < props.list.length; i++) {
		// 先铺上第一行(i < column 则表示是第一行)
		if (i < column) {
			props.list[i].top = 0;
			props.list[i].left = i * (width + (i > 0 ? rightGap : 0));
			// 塞进瀑布流
			waterList.value?.push(props.list[i]);
			// 高度数据更新
			heightList[i] = props.list[i].height;
		}
		// 后面的就要一张张塞进去,每次找出最低的列往里塞
		else {
			// 最低的高度,先默认为第一列高度
			let current = heightList[0];
			// 最低的列,先默认为第一个
			let col = 0;

			// 循环每一列进行比较
			heightList.forEach((h, i) => {
				if (h < current) {
					current = h;
					col = i;
				}
			});
			console.log('最低的列', col, '高度为', current);

			// 由此计算出该图片的 left、top
			props.list[i].left = col * (width + rightGap);
			props.list[i].top = current + gap;
			// 塞进瀑布流
			waterList.value.push(props.list[i]);

			// 更新列高度数组
			heightList[col] = current + gap + props.list[i].height;
		}
	}
	console.log('waterList', waterList.value);
	console.log('heightList', heightList);
});
</script>

4.设置瀑布流的相关样式

可根据个人需求进行调整,这里展示的是上方效果图的样式

<style lang="scss" scoped>
.list {
	position: relative;
	height: 100%;
	width: 100%;
	.item {
		position: absolute;
		.text-box {
			font-weight: 500;
			font-size: 18px;
			color: #000000;
		}
		img {
            width: 100%;
            height: 90%;
			object-fit: cover;
		}
	}
}
</style>

二、创建使用瀑布流的父组件

1.新建父组件,如命名为index.vue

2.创建父组件的展示内容,分为左侧的菜单和右侧的瀑布流内容

isMenuBarFixed为控制左侧菜单根据右侧滚动条进行滑动的属性,menu-bar里面的内容为左侧菜单的内容,works-box为右侧瀑布流的内容,中间的<div style="width: 160px" v-if="isMenuBarFixed"></div>为当左侧菜单脱离文档流的占位内容,关于脱离文档流,想要学习的同学可参考这篇博客:CSS标准文档流和脱离文档流_css脱离文档流-CSDN博客

<template>
	<div class="max-content">
		<div class="main-content">
			<div class="works-publicity">
				<nav class="menu-bar" ref="menuBar" :class="{ fixed: isMenuBarFixed }">
					<ul style="padding: 0">
						<li
							v-for="(item, index) in menuItems"
							:key="index"
							class="menu-item"
							@click="setActiveItem(index)"
							:class="{ active: activeIndex === index }"
						>
							<div class="menu-item-content">
								<div
									class="menu-item-border"
									:class="{ blue: activeIndex === index }"
								></div>
								<img
									:src="item.isActive ? item.activeImage : item.image"
									class="menu-icon"
									alt=""
								/>
								<div class="menu-text" :class="{ blue: activeIndex === index }">
									{{ item.text }}
								</div>
							</div>
						</li>
					</ul>
				</nav>
				<div style="width: 160px" v-if="isMenuBarFixed"></div>
				<div class="works-box" ref="myDiv">
					<water-fall :list="list" :boxWidth="boxWidth" class="water-fall" />
				</div>
			</div>
		</div>
	</div>
</template>

3.父组件的相关方法

控制左侧瀑布流菜单根据右侧滚动条固定的相关关键代码可参考本篇博客的缩略版使用vue3实现右侧瀑布流滑动时左侧菜单的固定与取消固定-CSDN博客

<script setup>
import { cloneDeep } from 'lodash-es';
const config = useRuntimeConfig();

const myDiv = ref(null);
const menuBar = ref(null);
const isMenuBarFixed = ref(false);
const boxWidth = ref(''); // 展示瀑布流的盒子的宽度
const menuItems = ref([
	{
		text: '第一个',
		image: '/images/works-publicity/industrial-design.png',
		activeImage: '/images/works-publicity/industrial-design-active.png',
		isActive: true,
	},
	{
		text: '第二个',
		image: '/images/works-publicity/handicrafts.png',
		activeImage: '/images/works-publicity/handicrafts-active.png',
		isActive: false,
	},
	{
		text: '第三个',
		image: '/images/works-publicity/painting.png',
		activeImage: '/images/works-publicity/painting-active.png',
		isActive: false,
	},
	{
		text: '第四个',
		image: '/images/works-publicity/photograph.png',
		activeImage: '/images/works-publicity/photograph-active.png',
		isActive: false,
	},
	{
		text: '第五个',
		image: '/images/works-publicity/geography.png',
		activeImage: '/images/works-publicity/geography-active.png',
		isActive: false,
	},
	{
		text: '第六个',
		image: '/images/works-publicity/tradition.png',
		activeImage: '/images/works-publicity/tradition-active.png',
		isActive: false,
	},
]);
const list = [
	{
		height: 450,
		background: 'red',
		image: '/images/works-publicity/test1.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 600,
		background: 'pink',
		text: '美术作品+沈佳宜',
		image: '/images/works-publicity/test2.png',
	},
	{
		height: 450,
		background: 'blue',
		image: '/images/works-publicity/test3.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 350,
		background: 'green',
		image: '/images/works-publicity/test4.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 500,
		background: 'gray',
		image: '/images/works-publicity/test5.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 400,
		background: '#CC00FF',
		image: '/images/works-publicity/test6.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 300,
		background: 'pink',
		image: '/images/works-publicity/test7.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 600,
		background: '#996666',
		image: '/images/works-publicity/test8.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 400,
		background: 'gray',
		image: '/images/works-publicity/test9.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 400,
		background: '#CC00FF',
		image: '/images/works-publicity/test10.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 500,
		background: 'gray',
		image: '/images/works-publicity/test11.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 300,
		background: '#996666',
		image: '/images/works-publicity/test12.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 600,
		background: 'gray',
		image: '/images/works-publicity/test13.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 400,
		background: '#CC00FF',
		image: '/images/works-publicity/test1.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 500,
		background: 'gray',
		image: '/images/works-publicity/test2.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 300,
		background: '#996666',
		image: '/images/works-publicity/test3.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 300,
		background: 'gray',
		image: '/images/works-publicity/test4.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 400,
		background: '#CC00FF',
		image: '/images/works-publicity/test5.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 500,
		background: 'gray',
		image: '/images/works-publicity/test6.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 400,
		background: '#996666',
		image: '/images/works-publicity/test7.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 350,
		background: 'gray',
		image: '/images/works-publicity/test8.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 450,
		background: '#CC00FF',
		image: '/images/works-publicity/test9.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 430,
		background: 'gray',
		image: '/images/works-publicity/test10.png',
		text: '平面作品+李宇轩',
	},
	{
		height: 600,
		background: '#996666',
		image: '/images/works-publicity/test11.png',
		text: '平面作品+李宇轩',
	},
];
const activeIndex = ref(0);
// 点击左侧菜单栏切换内容
const setActiveItem = (num) => {
	menuItems.value.forEach((item, idx) => {
		item.isActive = num === idx;
	});
	activeIndex.value = num;
};
// 监听滚动事件
const handleScroll = () => {
	const scrollTopThreshold = 428;
	const scrollTop = document.body.scrollTop; // 获取滚动位置
	if (scrollTop >= scrollTopThreshold) {
		isMenuBarFixed.value = true;
	} else {
		isMenuBarFixed.value = false;
	}
};


onMounted(async () => {
	await nextTick(); // 等待 DOM 更新
	boxWidth.value = myDiv.value.offsetWidth; // 确保 myDiv 已经被定义并且 DOM 已经渲染
	document.body.addEventListener('scroll', handleScroll); // 添加滚动事件监听器
});
// 组件卸载前
onUnmounted(() => {
	document.body.removeEventListener('scroll', handleScroll()); // 移除滚动事件监听器
});
</script>

4.父组件内容的相关样式

<style lang="scss" scoped>
.works-publicity {
	display: flex;
	width: 100%;
	padding: 20px 0;
	box-sizing: border-box;
	.menu-bar,
	.fixed {
		position: relative; /* 或者 static,取决于你的布局 */
		top: 0; /* 确保它在页面顶部开始 */
		transition: top 0.3s ease; /* 可选的过渡效果 */
		display: flex;
		justify-content: space-around; /* 根据需要调整菜单项间距 */
		list-style: none;
		padding: 0;
		.menu-item {
			display: flex;
			position: relative;
			align-items: center; /* 垂直居中图片和文字 */
			justify-content: center;
			cursor: pointer; /* 鼠标悬停时改变样式(可选) */
			width: 160px;
			height: 136px;
			text-align: center;
			border-left: 1px solid #d3dde9;
		}
		.menu-icon {
			width: 32px; /* 根据图标大小调整 */
			height: 32px; /* 根据图标大小调整 */
			margin-bottom: 20px; /* 图片和文字之间的间距 */
		}
		.menu-item-content {
			display: flex;
			align-items: center;
			flex-direction: column;
		}

		.menu-item-border {
			position: absolute;
			left: 0; /* 左边框位置 */
			top: 0; /* 可以根据需要调整 */
			bottom: 0; /* 可以根据需要调整 */
			width: 3px; /* 边框宽度 */
			background-color: transparent; /* 默认透明 */
		}

		.menu-item-border.blue {
			background-color: var(--el-color-primary); /* 激活时变为蓝色 */
		}
		.menu-text.blue {
			color: var(--el-color-primary); /* 激活时文字变为蓝色 */
		}
	}
	.fixed {
		/* 当固定时 */
		position: fixed;
		top: 0;
		width: 160px; /* 或者你需要的宽度 */
		z-index: 100; /* 确保它在其他内容之上 */
		/* 其他样式,可能需要调整以适应固定定位 */
	}
	.works-box {
		display: flex;
		flex-direction: column;
		width: 100%;
		.water-fall {
			margin-top: 30px;
		}
	}
}
</style>

这样,关于瀑布流的展示及滚动条滑动时,左侧菜单的灵活固定就完成啦!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

驱动命令之insmod depmod modprobe rmmod modinfo lsmod

insmod命令 insmod需指定所需加载模块的路径&#xff0c;且只加载所指定的模块&#xff0c;如果所指定的模块依赖于其他模块&#xff0c;insmod不会自动添加&#xff1b; 语法 insmod [-fkmpsvxX][-o <模块名称>][模块文件][符号名称 符号值] 参数说明&#xff1a; -f…

【代码随想录训练营】【Day 29】【回溯-3】| Leetcode 39, 41, 131

【代码随想录训练营】【Day 29】【回溯-3】| Leetcode 39&#xff0c; 41&#xff0c; 131 需强化知识点 startInex作用&#xff1a;一是处理是否可以有重复值&#xff0c;二是实现纵向遍历&#xff08;不能没有&#xff09;去重要在数组有序的前提下进行分割问题 题目 39.…

Comfyui工作流报错:Image scale to side 报错,安装了Derfuu-Nodes仍然没法运行

&#x1f386;问题描述 最近很多朋友在玩comfyui的时候&#xff0c;发现有个图像缩放的节点用不了了&#xff0c;同时报错&#xff1a; When loading the graph, the following node types were not found: Image scale to side Nodes that have failed to load will show as…

数据结构之栈和队列(超详解

目录 一.栈 1.栈的基本概念 2.栈的基本操作 3.栈的储存结构 ①栈的顺序储存 (1)基本概念 (2)代码实现 ②栈的链式储存 (1)基本概念 (2)代码实现 二.队列 1.队列的基本概念 2.队列的基本操作 3.队列的储存结构 ①队列的链式储存 (1)基本概念 ​编辑 (2)代码实现 ②…

C++进阶之路:何为拷贝构造函数,深入理解浅拷贝与深拷贝(类与对象_中篇)

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

Java的线程的使用

一.两种创建线程的方式 1.继承Thread类&#xff08;匿名内部类&#xff09; 创建方式&#xff1a; 1.定义一个子类继承Thread&#xff0c;重写run方法 2.创建子类对象&#xff0c; 3.调用子类对象的start方法&#xff08;启动还是执行的run方法&#xff09; 优缺点&#x…

小猪APP分发:一站式免费应用推广解决方案

在竞争激烈的移动应用市场中&#xff0c;寻找一个高效且成本友好的方式来推广自己的应用程序&#xff0c;成为了众多开发者面临的共同挑战。幸运的是&#xff0c;像"小猪APP分发www.appzhu.cn"这样的平台应运而生&#xff0c;为开发者提供了一个全面、免费的应用分发…

论文精读:HuggingGPT: Solving AI Tasks with ChatGPT and its Friends in Hugging Face

HuggingGPT: Solving AI Tasks with ChatGPT and its Friends in Hugging Face Status: Reading Author: Dongsheng Li, Kaitao Song, Weiming Lu, Xu Tan, Yongliang Shen, Yueting Zhuang Institution: 微软亚洲研究院&#xff08;Microsoft Research Asia&#xff09;, 浙江…

NLP(19)--大模型发展(3)

前言 仅记录学习过程&#xff0c;有问题欢迎讨论 大模型训练相关知识&#xff1a; 问题&#xff1a; 数据集过大&#xff0c;快速训练模型过大&#xff0c;gpu跑不完 方案&#xff1a; 数据并行训练&#xff1a; 复制数据&#xff08;batch_size&#xff09;到多个gpu&…

机器学习实验------Adaboost算法

第1关&#xff1a;什么是集成学习 任务描述 本关任务&#xff1a;根据本节课所学知识完成本关所设置的选择题。 第2关&#xff1a; Boosting 任务描述 本关任务&#xff1a;根据本节课所学知识完成本关所设置的选择题。 第3关&#xff1a;Adaboost算法流程 任务描述 …

C++学习/复习4--与类相关的概念/默认成员函数/运算符重载/Date类实现案例

一、类和对象 1.本章概要 2.C中的结构体(struct与class) 升级为类 &#xff08;1&#xff09;类及成员函数的两种定义方式 声明与定义分离 &#xff08;2&#xff09;权限 注意1&#xff1a;struct/class在权限上的区别 &#xff08;3&#xff09;封装 &#xff08;4&#x…

连公司WiFi后,无法访问外网,怎么回事,如何解决?

文章目录 封面问题描述问题探究什么是DNS&#xff1f;分布式&#xff0c;层次数据库如何理解分布式&#xff1f;如何理解层次&#xff1f; 本地DNS服务器迭代查询&#xff0c;递归查询DNS缓存参考资料 封面 问题描述 从甲方项目组返回公司后&#xff0c;我习惯性连上公司WiFi&…

50 http通用服务器

虽然我们说&#xff0c;应用层协议是我们程序猿自己定的 但实际上&#xff0c;已经有大佬们定义了一些现成的&#xff0c;又非常好用的应用层协议&#xff0c;供我们直接参考使用&#xff0c;http&#xff08;超文本传输协议&#xff09;就是其中之一 目录 认识urlurlencode和…

数据库(5)——DDL 表操作

表查询 先要进入到某一个数据库中才可使用这些指令。 SHOW TABLES; 可查询当前数据库中所有的表。 表创建 CREATE TABLE 表名( 字段1 类型 [COMMENT 字段1注释] ...... 字段n 类型 [COMMENT 字段n注释] )[COMMENT 表注释]; 例如&#xff0c;在student数据库里创建一张studen…

LeetCode热题100——矩阵

73.矩阵清零 题目 给定一个 *m* x *n* 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]] 示例…

记.netcore部署到银河麒麟linux服务器过程详解

一.服务器配置 操作系统:银河麒麟桌面操作系统V10 CPU:intel i5 内存:16G 内核:5.10.0.8-generic 未激活 二.运行环境安装 .netcore 6.0 runtime时安装下载离线包 Download .NET 6.0 (Linux, macOS, and Windows) -下载完后进行解压 sudo su #提权 mkdir -p $HOME/…

救援运输车3D三维虚拟展馆能分享给更多潜在买家

随着消费趋势的演进&#xff0c;个性化和附加服务需求日益凸显。加上疫情等因素影响下&#xff0c;一场创新的革命正在悄然兴起——3D沉浸式看车。 3D沉浸式看车&#xff0c;重新定义购车体验 不再受限于地理位置和时间&#xff0c;3D沉浸式看车是利用web3d开发建模技术将真实比…

C# 机构仿真实例

1、实现连杆带动滑块运动 一个连杆旋转带动另一个连杆&#xff0c;另一个连杆拖动滑块&#xff0c;点击“开始”按钮开始运动&#xff0c;再点击按钮&#xff0c;则停止运动。 2、实现程序 #region 机构仿真Image image null;Timer timer new Timer();int width 0;int heig…

一个机器学习问题的重新定义

任何事物都有两面性。 一些机器学习问题也是如此。并非每个回归问题&#xff08;你认为的&#xff09;都需要回归。仔细考虑和审视问题的业务不仅可以帮助开发更好的模型&#xff0c;还可以找到有效的解决方案。 重构或重新定义&#xff08;reframing&#xff09;是一种改变机…