vue3 弹窗开发之三,完善版

news2024/11/22 21:39:08

首先我们看一看整体的效果

 

 点击图一的缩略图,查看大图(如图二)。同时弹窗内容底下有当前所有图片的缩略图展示,同时通过一个橙色的边框定位当前缩略图的位置。切换左右箭头滚动下一站或者上一张,同时底下缩略图同步有个激活样式,切换至第一张点击不再向前切换,点击右侧按钮同理。

先来说下基本思路:

1 整个弹窗我们通过teleport来实现

2 底下的缩略图我们通过el-scroll这个组件来实现,至于点击切换,则是我们通过index索引找到图片,当前前提是我们必须要图一的列表传入到弹层组件里面。

3 点击左右按钮,我们给index++或者--,底下的缩略图的联动则是通过el-scroll的setScrollLeft(number)来实现。每次滚动的距离则是通过当前这张图的索引*缩略图本身的宽度

我们把图一中的每个卡片item封装成一个组件。名曰RenderItem

那么图一的结果就如下:

<div class="render-list">
					<RenderItem v-for="item in list" :key="item.id" :data="item" :imgList="list" @del="delData" />
					<div class="vis" v-for="num in 4" :key="num"></div>
</div>

const arr = [
	{
		id: "001",
		title: "111111",
		url: "https://baj-dabanjiz-conf.oss-accelerate.aliyuncs.com/pano/85875_1641469258147/MuliplePano_thumbnail_1641469245589.jpg",
		spaceName: "主卧"
	},
	{
		id: "002",
		title: "111111",
		url: "http://baj-dabanjiz-conf.oss-cn-hangzhou.aliyuncs.com/promotion/assistant/setmeal/5/%E5%B0%81%E9%9D%A2.png",
		spaceName: "次卧"
	}]

我们再看看renderItem内部的核心代码:

	<RenderImgDialog v-if="isView" :index="curIndex" :imgList="picList" @close="toggleRenderImg(false)" />
</template>
<script setup lang="ts">
const isShow = ref<boolean>(false);
const isComplete = ref<boolean>(true);
const isView = ref<boolean>(false);
const curIndex = ref<number>(0);

interface renderItem {
	id: string;
	title: string;
	url: string;
	spaceName: string;
	checked?: boolean;
}
const emits = defineEmits(["del"]);

const props = defineProps({
	data: {
		type: Object,
		default: () => {}
	},
	imgList: {
		type: Array,
		default: () => []
	}
});

const picList = computed(() => {
	return props.imgList.map(item => item?.url);
});

watch(
	() => props.data.checked,
	(n: boolean): void => {
		console.log("n---", n);
		n ? (isShow.value = true) : (isShow.value = false);
		console.log("isShow:", isShow.value);
		console.log("imgList:", props.imgList);
	}
);


const toggleRenderImg = (flag: boolean) => {
	isView.value = flag;
	let res = props.imgList;
	//根据id-->当前图片的index
	let tempIndex = 0;
	props.imgList.forEach((item, index): void => {
		if (item.id == props.data.id) {
			tempIndex = index;
		}
	});
	curIndex.value = tempIndex;
	console.log("tempIndex:", tempIndex);
};

我们把图二的弹窗封装成了一个组件,名曰RenderImgDialog。然后通过isView来控制它是否展示。然后我们点击图一的某张卡片图的时候给他传入当前图片的索引和图片的列表

接下来我们看看RenderImgDialog里面是怎么做的?

<template>
	<teleport to="#app">
		<!-- <transition name="el-fade-in-linear"> -->
		<div>
			<div class="mask"></div>
			<div class="modal">
				<div class="container">
					<div class="modal-head">
						<div class="modal-title">标题部分</div>
						<div class="close-icon" @click="close">
							<el-icon><CloseBold /></el-icon>
						</div>
					</div>
					<div class="content">
						<div class="lt-arrow" @click="prev">
							<el-icon><ArrowLeftBold /></el-icon>
						</div>
						<div class="mid-imgWrap" ref="mainImgRef">
							<el-image :src="curSrc" fit="cover" style="width: 812px; height: 534px"></el-image>
						</div>
						<div class="rt-arrow" @click="next">
							<el-icon><ArrowRightBold /></el-icon>
						</div>
					</div>
					<div class="desc-wrap">
						<el-tooltip placement="top-start" effect="light">
							<template #content>
								<h2 class="tip-title">图片信息</h2>
								<div>
									<el-descriptions title="User Info" direction="vertical" :column="2" :width="72" size="small">
										<el-descriptions-item label="空间">全屋</el-descriptions-item>
										<el-descriptions-item label="包含商品">18100000000</el-descriptions-item>
										<el-descriptions-item label="方案介绍">Suzhou</el-descriptions-item>
										<el-descriptions-item label="生成时间">
											<el-tag size="small">School</el-tag>
										</el-descriptions-item>
										<el-descriptions-item label="有效期">No.1188, Wuzhong Avenue,</el-descriptions-item>
									</el-descriptions>
								</div>
							</template>
							<el-icon class="item-icon"><InfoFilled /></el-icon>
						</el-tooltip>
						<el-tooltip content="全屏" placement="top-start" effect="light">
							<el-icon class="item-icon"><ScaleToOriginal /></el-icon>
						</el-tooltip>
						<el-tooltip content="分享" placement="top-start" effect="light">
							<el-icon class="item-icon"><Share /></el-icon>
						</el-tooltip>
						<el-tooltip content="删除" placement="top-start" effect="light">
							<el-icon class="item-icon"><Delete /></el-icon>
						</el-tooltip>
						<el-tooltip content="下载" placement="top-start" effect="light">
							<el-icon class="item-icon"><Download /></el-icon>
						</el-tooltip>
						<el-tooltip content="设置" placement="top-start" effect="light">
							<el-icon class="item-icon"
								><el-icon><Setting /></el-icon
							></el-icon>
						</el-tooltip>
						<span class="line">|</span>
						<span @click="toggleThumb">
							<el-icon :class="isFold ? 'arrow-down' : 'arrow-up'"><ArrowDownBold /></el-icon>
							<span class="fold">收起缩略图</span>
						</span>
					</div>
					<!-- <transition name="el-fade-in-linear"> -->
					<!-- <section class="thumb-wrap" > -->
					<el-scrollbar :class="isFold ? 'vis' : ''" wrap-style="margin-left:20px" ref="refScrollbar">
						<div class="thumn-inner-wrap">
							<div :class="[{ active: k == idx }, 'thumb-img']" v-for="(item, k) in imgList" :key="k">
								<img :src="item" class="imgObj" />
							</div>
						</div>
					</el-scrollbar>
					<!-- </section> -->
					<!-- </transition> -->
				</div>
			</div>
		</div>
		<!-- </transition> -->
	</teleport>
</template>

<script setup lang="ts">
interface RenderProsp {
	isShow?: boolean;
	index?: number;
	imgList?: string[];
}
const props = withDefaults(defineProps<RenderProsp>(), {
	isShow: false,
	index: 0,
	imgList: () => []
});
const emit = defineEmits(["close", "update:isShow"]);
const idx = ref<number>(0);
const isFold = ref<boolean>(false);
const scrollDis = ref<number>(0);
const curSrc = computed(() => {
	return props.imgList[idx.value];
});
const refScrollbar = ref<any>(null);
const mainImgRef = ref<any>(null);
const originListLen = toRaw(props.imgList.length);

onMounted(() => {
	idx.value = props.index;
	scrollDis.value = props.index * 200;
	console.log("scrollDis.value:", scrollDis.value);

	nextTick(() => {
		// if (refScrollbar?.value?.setScrollLeft) {
		let bar = refScrollbar.value;
		console.log("bar", bar);
		refScrollbar?.value?.setScrollLeft(scrollDis.value);
		mainImgRef?.value?.addEventListener("selectstart", () => {
			return false;
		});
		// }
	});
});
watch(
	() => props.index,
	n => {
		idx.value = n;
		scrollDis.value = n * 200;
		refScrollbar?.value?.setScrollLeft(scrollDis.value);
	}
);
const next = (): void => {
	if (idx.value >= originListLen - 1) {
		scrollDis.value = 200 * originListLen;
		return;
	} else {
		scrollDis.value += 200;
		idx.value++;
	}
	console.log("index:", idx.value);
	console.log("scrollDis.value:", scrollDis.value);
	if (refScrollbar.value) {
		refScrollbar.value!.setScrollLeft(scrollDis.value);
	}
};
const prev = (): void => {
	if (idx.value <= 0) {
		scrollDis.value = 0;
		nextTick(() => {
			// refScrollbar.value.setScrollLeft(0);
		});
		return;
	} else {
		idx.value--;
		scrollDis.value -= 200;
	}
	console.log("index:", idx.value);
	console.log("scrollDis.value:", scrollDis.value);
	refScrollbar.value.setScrollLeft(scrollDis.value);
};

const close = () => {
	emit("close", false);
	// emit("update:isShow", false);
};
const toggleThumb = (): void => {
	isFold.value = !isFold.value;
	console.log("isFold.value", isFold.value);
};
</script>
<style scoped>
.modal {
	width: 1020px;
	height: 819px;
	opacity: 1;
	border-radius: 8px;
	background: rgba(41, 42, 46, 1);
	position: fixed;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	z-index: 100;
}
.mask {
	width: 100%;
	height: 100%;
	position: fixed;
	top: 0;
	left: 0;
	background: rgba(0, 0, 0, 1);
	z-index: 99;
}
.modal-head {
	padding: 25px 0 23px 0;
	box-sizing: border-box;
	display: flex;
	text-align: center;
}
.modal-title {
	width: 90%;
}
.close-icon {
	flex: 1;
	padding-right: 24px;
	box-sizing: border-box;
}
.content {
	display: flex;
}
.close-icon {
	display: flex;
	justify-content: flex-end;
}
.mid-imgWrap {
	width: 812px;
	height: 534px;
	flex-shrink: 0;
	-webkit-user-select: none;
}
.lt-arrow,
.rt-arrow {
	flex: 1;
	display: flex;
	flex-direction: column;
	justify-content: center;
	align-items: center;
}
.desc-wrap {
	text-align: center;
	padding: 25px 0;
}
.tip-title {
	font-size: 14px;
	font-weight: 600;
	margin-bottom: 16px;
}
.item-icon {
	margin-left: 24px;
	font-size: 22px;
}
.fold {
	color: rgba(255, 255, 255, 0.6);
	font-size: 14px;
	margin-left: 4px;
	vertical-align: baseline;
}
.line {
	display: inline-block;
	margin: 0 24px;
	padding-top: -10px;
	color: #fff;
	opacity: 0.2;
}
.thumb-wrap {
	width: 100%;
	height: 118px;
	padding-left: 20px;
	box-sizing: border-box;
	overflow-x: scroll;
	overflow-y: hidden;
}
.thumn-inner-wrap {
	/* width: 200%; */
	display: flex;
	height: 118px;
	box-sizing: border-box;
	transition: all 0.1s ease-in;
	/* overflow-y: hidden; */
	/* flex-wrap: wrap; */
}
.thumn-inner-wrap::-webkit-scrollbar {
	width: 1px; /*高宽分别对应横竖滚动条的尺寸*/
	height: 1px;
}

.thumn-inner-wrap::-webkit-scrollbar-thumb {
	background: #fff;
}
.thumn-inner-wrap::-webkit-scrollbar-button {
	background: #f00;
}
.thumb-img {
	width: 180px;
	height: 118px;
	background: #ccc;
	margin-right: 10px;
	flex-shrink: 0;
	margin-right: 10px;
	display: flex;
	justify-content: center;
}
.imgObj {
	max-width: 100%;
	max-height: 100%;
	object-fit: cover;
}
.active {
	border: 2px solid rgba(254, 113, 0, 1);
}
.arrow-down {
	width: 16px;
	height: 16px;
	display: inline-block;
	animation: down 0.3s forwards;
}
.arrow-up {
	width: 16px;
	height: 16px;
	display: inline-block;
	animation: up 0.3s forwards;
}

@keyframes down {
	0% {
		transform: rotate(0deg);
	}
	100% {
		transform: rotate(180deg);
	}
}

@keyframes up {
	0% {
		transform: rotate(90deg);
	}
	100% {
		transform: rotate(0deg);
	}
}
.scroll-dom {
	transition: all 0.3s linear;
}
.vis {
	height: 0;
}
</style>

预览弹窗的组件里注意看curSrc,我们通过index得到当前list中的图片地址,然后监听props.index,为了避免数据流的混乱,我们在组件内部定义了一个idx的ref,初始化的时候把props.index赋值给他,props.index被监听每次变化的时候再次做赋值。所有切换的操作根据idx值的变化来动态更改。最后就是底下缩略图的定位问题。其实只要每次切换上一张下一张的时候我们更改idx,同时通过el-scroll提供的setScrollLeft设置其值就可以了。而这个值就是当前idx*缩略图本身的宽度

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

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

相关文章

mybatis的xml中<trim>标签的用法

文章目录1. 前言2. 先说结论3. 验证1. 情况一2. 情况二3. 情况三4. 情况四5. 验证prefixOverrides去掉的是trim内原sql内容1. 前言 在工作中离不开跟数据库打交道&#xff0c;目前流行的固然是mybatis&#xff0c;在xml中写sql的时候&#xff0c;可能会出现下面情况&#xff1a…

线性表的顺序实现【C语言版的真代码】

顺序表线性表顺序表顺序表的概念及其结构顺序表基本操作顺序表的初始化顺序表的插入顺序表的删除顺序表的查找线性表 线性表&#xff1a;一个线性表是含n个数据元素的有限序列。 它的逻辑结构要求是线性的&#xff0c;但其存储结构并没有做要求&#xff0c;即逻辑结构类似于如…

非DBA人员从零到一,MySQL InnoDB数据库调优之路(四)-数据备份与迁移

上一篇【非DBA人员从零到一&#xff0c;MySQL InnoDB数据库调优之路(三)-分区表与分库分表】 我认为分表在数据库的调优中是一种加法&#xff0c;通过拆分单表数据到多个表中&#xff0c;减少单表的压力&#xff0c;从而达到调优的效果&#xff0c;那么这一篇博文会通过对数据…

Spring Security权限管理原理

1.简介 授权是更具系统提前设置好的规则&#xff0c;给用户分配可以访问某一资源的权限&#xff0c;用户根据自己所具有的权限&#xff0c;去执行相应的操作&#xff0c;spring security提供的权限管理功能主要有两种&#xff1a; 基于过滤器的权限管理功能&#xff08;Filte…

Syntax Error: Error: Missing binary. See message above.

安装完nvm&#xff0c;选择后node版本&#xff0c;在idea中引入vue项目&#xff0c;npm install后&#xff0c;运行npm run serve后 控制台出现下面错误&#xff1a; Try running this to fix the issue: D:\Program Files\nodejs\node.exe E:\vue-project\node_modules\fibe…

篮球竞赛预约平台设计与实现的源码+文档

摘 要 随着信息化时代的到来&#xff0c;管理系统都趋向于智能化、系统化&#xff0c;篮球竞赛预约平台也不例外&#xff0c;但目前国内仍都使用人工管理&#xff0c;市场规模越来越大&#xff0c;同时信息量也越来越庞大&#xff0c;人工管理显然已无法应对时代的变化&#x…

platform总线

1、什么是platform总线&#xff1f; platform是Linux内核抽象出来的软件代码&#xff0c;用于设备与驱动的连接&#xff0c;设备与驱动通过总线进行匹配&#xff1b;匹配成功后会执行驱动中的probe函数&#xff0c;在probe函数中可以获取到设备的信息&#xff1b; 设备与驱动…

gitlab的使用方法,详解gitlab操作

1.导读 本教程主要讲解了GitLab在项目的环境搭建和基本的使用&#xff0c;可以帮助大家在企业中能够自主搭建GitLab服务&#xff0c;并且可以GitLab中的组、权限、项目自主操作。 - GitLab简介 - GitLab环境搭建 - GitLab基本使用(组、权限、用户、项目) 2.GitLab简介 Gi…

debug - JLX12864C(ST7920-12864)液晶屏不能使用串行通讯的原因

文章目录debug - JLX12864C(ST7920-12864)液晶屏不能使用串行通讯的原因概述调试备注ENDdebug - JLX12864C(ST7920-12864)液晶屏不能使用串行通讯的原因 概述 正在给板子写出厂测试程序, 买的12864型号是JLX12864C. STC官方给的例程是并行通讯, 好使. 但是想在测试程序中改为…

Linux线程基础

目录 一&#xff0c;线程函数 1、创建一个线程 2、获取自身线程ID 3、线程终止 4、取消正在执行线程 5、线程等待 6、线程分离 二&#xff0c;线程的使用 1&#xff0c;线程等待和线程分离 (1)、线程等待 (2)、线程分离 (3)、线程等待线程分离同时进行 三&#xff…

中英翻译《森林火灾的预防措施》

The Preventive Measures for Forest Fire 森林火灾的预防措施 The preventive measures for forest fires include some preemptive methods that can help reduce the risks of fires and contril their severity and spread, and thus, maintain ecological balance …

vue与es6的知识点

var let const let const 不能重复声明&#xff0c;局部作用域&#xff0c; 案例 let name "未来"; let str 我是${name}; console.log(str); 箭头函数 let add (x)>{ return x; } console.log(add(9)) v-bind 绑定标签的属性 src class a titie等等…

Qt for Android实现开机自启动

前言 最近项目需要&#xff0c;在Android上编写的程序&#xff0c;需要实现开机自启动。笔者查询了下资料&#xff0c;基本原理如下&#xff1a; 当Android启动时&#xff0c;会发出一个系统广播&#xff0c;内容为ACTION_BOOT_COMPLETED&#xff0c;它的字符串常量表示为 an…

详解时间复杂度计算公式(附例题细致讲解过程)

这几天开始刷力扣上面的算法题&#xff0c;有些题目上面限制时间复杂度和空间复杂度&#xff0c;题目虽然写出来了&#xff0c;但是很没底。印象里数据结构老师讲过一点&#xff0c;沉睡的记忆苏醒了。只记得一个时间复杂度是O(n)&#xff0c;空间复杂度是S(n)。for循环常常是O…

中学语文教学参考杂志社中学语文教学参考编辑部2022年第27期目录

理论学术_课题荟萃《中学语文教学参考》投稿&#xff1a;cn7kantougao163.com 统编教材鲁迅作品的民俗文化分析及教学应用 张家波;张晓静; 3-5 高中语文线上学习的实践与反思 张灵贵; 6-797 不同课型导学案设计建议 张桂霞; 8-997 现代化进程中的阵痛:《哦,香雪…

遇到Bug漏测,不能总想着甩锅吧

背景 漏测Bug是指产品逻辑缺陷在测试过程中没有被发现&#xff08;尤其是测试环境可以重现的缺陷&#xff09;&#xff0c;上线版本发布后或者在用户使用体验后发现并反馈回来的缺陷。 漏测Bug可能造成线上故障或者资损&#xff0c;在对产品测试过程中&#xff0c;自己也难免…

Pandas常见筛选数据的五种方法其一逻辑筛选。看见必懂,懂者必会,会者必加分

前言&#xff1a;Pandas的数据操作中&#xff0c;最基本的就是操作的筛选了&#xff0c;但是对新学员来说的这又是一个难点&#xff0c;因为方法比较多&#xff0c;不容易记。在此总结一下pandas中的一些常用的数据筛选操作。 逻辑筛选数据&#xff1a;切片&#xff08;[ ]&am…

ubuntu 安装、配置FTP

ubuntu 安装、配置FTP 提示&#xff1a;ubuntu 16.0.4&#xff0c;不同版本操作可能稍有不同 前言 本文主要对服务器安装及配置FTP做一个记录&#xff0c;涉及安装、配置、创建FTP账号、以及第一次连接异常等。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可…

单载波频域均衡matlab仿真,包括卷积编码维特比译码,矩阵交织,QPSK调制解调,导频插入,MMSE-FDE频域均衡

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 频域均衡是从校正系统的频率特性出发&#xff0c;利用一个可调滤波器的频率的频率特性去补偿信道或系统的频率特性&#xff0c;使包括可调滤波器在内的基带系统的总特性接近无失真传输条件。频域…

【Spring项目中的Controller理解】

目录 1. 添加依赖 2. 关于异常 1. 添加依赖 首先&#xff0c;需要保障此项目中存在spring-boot-starter-web依赖项&#xff0c;否则&#xff0c;当前项目并不具备Web应用程序开发所需的依赖&#xff01; 提示&#xff1a;spring-boot-starter-web是建立在spring-boot-starte…