vue3实现轮播渲染多张图每张进行放大缩小拖拽功能互不影响

vue3实现轮播渲染多张图每张进行放大缩小拖拽功能互不影响

1.以vue3中el-carousel轮播插件为例

 <div class="pic_view"><el-carousel height="100vh" :autoplay="false" ref="carouselRef" @change="handleCarouselChange"><el-carousel-item v-for="item in picLists" :key="item.id" :data-id="item.id"><div :style="{ backgroundColor: item.backgroundColor }" @wheel.prevent="rollImg" class="pic_set":data-id="item.id" ref="picSetRefs"><img :src="getUrl(`${item.url}`)" class="img" @mousedown="startMove($event, item.id)" :style="{left: imgStates[item.id]?.position.x || '25%',top: imgStates[item.id]?.position.y || '0',transform: `scale(${imgStates[item.id]?.zoom || 1})`}" /></div></el-carousel-item></el-carousel></div>

注意:getUrl方法是vite处理静态资源图片的,由于是本地为了测试,你们拿例子的时候注意点可以去掉这个方法放你们本地路径渲染

2.事件

<script setup>
import { ref, reactive, onMounted, onBeforeUnmount, nextTick } from 'vue'
import { getImageUrl } from '@/utils/pub-use'const getUrl = getImageUrlconst picLists = reactive([{ id: 1, url: 'yu1.webp', backgroundColor: '#6f6865' },{ id: 2, url: 'yu2.webp', backgroundColor: '#726A67' },{ id: 3, url: 'yu3.webp', backgroundColor: '#705947' },
])// 存储每个图片的状态
const imgStates = reactive({})
const picSetRefs = ref([])
let currentImgId = ref(null)
let isDragging = false
let startX = 0
let startY = 0
let currentImgElement = null
let currentImgRect = null
let initialOffsetX = 0
let initialOffsetY = 0
// yzm提示:由于一般方法只适用单张,特此整合渲染多张图操作
// 初始化图片状态
const initImgState = (id) => {if (!imgStates[id]) {imgStates[id] = {zoom: 0.8,position: { x: '25%', y: '0' },positionConverted: false}}
}// 将百分比位置转换为像素值
const convertPositionToPixels = (id, element) => {const state = imgStates[id]if (!state || state.positionConverted) returnconst parent = element.parentElementif (!parent) return// 转换水平位置if (typeof state.position.x === 'string' && state.position.x.includes('%')) {const percent = parseFloat(state.position.x)state.position.x = `${(percent / 100) * parent.clientWidth}px`}// 转换垂直位置if (typeof state.position.y === 'string' && state.position.y.includes('%')) {const percent = parseFloat(state.position.y)state.position.y = `${(percent / 100) * parent.clientHeight}px`}// 更新元素样式element.style.left = state.position.xelement.style.top = state.position.ystate.positionConverted = true
}// 轮播切换时更新当前图片ID
const handleCarouselChange = (currentIndex) => {currentImgId.value = picLists[currentIndex].id// 确保新激活的图片位置已转换nextTick(() => {const activeIndex = currentIndexif (picSetRefs.value[activeIndex]) {const img = picSetRefs.value[activeIndex].querySelector('.img')if (img) {convertPositionToPixels(picLists[activeIndex].id, img)}}})
}// 拖动图片相关函数
const startMove = (e, id) => {currentImgId.value = idinitImgState(id)currentImgElement = e.currentTarget// 确保位置已转换为像素值if (!imgStates[id].positionConverted) {convertPositionToPixels(id, currentImgElement)}e.preventDefault()isDragging = true// 获取当前图片的位置和尺寸currentImgRect = currentImgElement.getBoundingClientRect()// 计算初始位置(直接使用状态中的像素值)initialOffsetX = parseFloat(imgStates[id].position.x || '0')initialOffsetY = parseFloat(imgStates[id].position.y || '0')// 计算鼠标在图片中的位置startX = e.clientX - currentImgRect.leftstartY = e.clientY - currentImgRect.topdocument.addEventListener('mousemove', move)document.addEventListener('mouseup', stopMove)
}const move = (e) => {if (!isDragging || !currentImgId.value || !currentImgElement) return// 计算新的位置(考虑缩放)const zoom = imgStates[currentImgId.value].zoom || 1const newX = initialOffsetX + (e.clientX - currentImgRect.left - startX) / zoomconst newY = initialOffsetY + (e.clientY - currentImgRect.top - startY) / zoom// 更新位置imgStates[currentImgId.value].position = {x: `${newX}px`,y: `${newY}px`}currentImgElement.style.left = `${newX}px`currentImgElement.style.top = `${newY}px`
}const stopMove = () => {isDragging = falsecurrentImgElement = nulldocument.removeEventListener('mousemove', move)document.removeEventListener('mouseup', stopMove)
}// 缩放图片
const rollImg = (e) => {// 获取事件发生的轮播项IDconst itemId = parseInt(e.currentTarget.getAttribute('data-id'))if (itemId !== currentImgId.value) returninitImgState(itemId)// 获取当前操作的图片元素const img = e.currentTarget.querySelector('.img')if (!img) return// 确保位置已转换为像素值if (!imgStates[itemId].positionConverted) {convertPositionToPixels(itemId, img)}// 获取当前缩放值const transform = img.style.transform || ''let zoom = imgStates[itemId].zoomif (transform.includes('scale')) {const match = transform.match(/scale\(([\d.]+)\)/)if (match && match[1]) {zoom = parseFloat(match[1])}}// 根据滚轮方向调整缩放const delta = e.deltaY || e.wheelDeltaconst direction = delta > 0 ? -1 : 1zoom += direction * 0.1// 限制缩放范围zoom = Math.max(0.1, Math.min(zoom, 5))// 更新状态和样式imgStates[itemId].zoom = zoomimg.style.transform = `scale(${zoom})`e.preventDefault()
}// 组件卸载时清除事件
onBeforeUnmount(() => {stopMove()
})// 初始化所有图片状态
onMounted(() => {picLists.forEach(item => {initImgState(item.id)})// 设置初始当前图片IDif (picLists.length > 0) {currentImgId.value = picLists[0].id}nextTick(() => {if (picSetRefs.value[0]) {const img = picSetRefs.value[0].querySelector('.img')if (img) {convertPositionToPixels(picLists[0].id, img)}}})
})
</script>

我给每张图片设置不同背景,这个也要注意,不需要的话可以在HTML代码块里把背景操作去掉,geturl这个是我自己封装的工具文件,你们用不到这个可以删掉把图片地址弄对就行

样式

<style scoped lang="scss">
.pic_view {height: 100vh;overflow: hidden;:deep(.el-carousel) {height: 100%;.el-carousel__container {height: 100%;}.el-carousel__item {display: flex;justify-content: center;align-items: center;}}
}.pic_set {position: relative;width: 100%;height: 100%;overflow: hidden;display: flex;justify-content: center;align-items: center;touch-action: none;.img {position: absolute;height: 100%;max-width: 900px;min-height: 400px;margin-left: 2%;cursor: move;transform-origin: center center;transition: transform 0.1s ease;user-select: none;will-change: transform;}.imgLow {width: 100%;height: 80px;margin-top: 30vh;}
}
</style>

样式加了过度以及中心放大缩小,看更加丝滑

以上就是三块区域代码

效果

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

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

相关文章

traceroute 使用说明

1、概述 Traceroute&#xff08;Windows 系统中为 tracert&#xff09;是一种网络诊断工具&#xff0c;用于跟踪数据包从本地设备到目标主机的传输路径&#xff0c;并显示沿途经过的每一跳&#xff08;路由器&#xff09;的延迟和 IP 地址。它通过发送不同 TTL&#xff08;生存…

用idea操作git缓存区回退、本地库回退、远程库回退

前言 使用idea软件操作git非常人性化和方便。 但是如果我的代码使用git提交之后,我想回到以前的版本,此时需要进行git的版本回退。 提交代码分为提交到缓存区、本地库、远程库这3个过程。 下面我将介绍每个阶段的提交对应的回退方法。 本篇文章是掌握git和使用idea操作git…

webpack+vite前端构建工具 - 3webpack处理js

3 webpack处理js webpack的核心——处理js文件&#xff0c;将模块化的代码打包。具体操作如下 es6转化&#xff08;为兼容老浏览器&#xff0c;将es6转化为es5&#xff09; babel-loader 代码规范&#xff08;例如空格&#xff0c;缩进等代码风格规范&#xff09; eslint 代码…

Nginx转发中相对路径资源302问题的分析与解决

Nginx转发中相对路径资源302问题的分析与解决 典型案例&#xff1a;后端页面引入./test.css的302问题 问题场景 假设我们有一个后端服务&#xff0c;其页面中通过相对路径引入了CSS文件&#xff1a; <!-- 后端页面代码 --> <link rel"stylesheet" href&…

Vue3 + TypeScript合并两个列表到目标列表,并且进行排序,数组合并、集合合并、列表合并、list合并

在Vue 3 TypeScript中合并并排序两个列表&#xff0c;可以通过以下步骤实现&#xff1a; 解决方案代码 vue 复制 下载 <script setup lang"ts"> import { ref, computed } from vue;// 定义列表项类型 interface ListItem {id: number;name: string;valu…

Python-教程

1 需求 2 接口 3 示例 4 参考资料 Python 教程 — Python 3.13.5 文档

Excel数据导出小记

文章目录 前言一、DataTable >EXCEL二、DBReader >Excel &#xff08;NPOI&#xff09;三、分页查询 DbReader>Excel (MiniExcel)总结&#xff1a; 前言 最近经历了一次数据量比较大的导出&#xff0c;也做了各种优化尝试&#xff0c;这里稍记录一下 一、DataTable …

深入理解链表数据结构:从Java LinkedList到自定义实现

引言 链表作为基础数据结构之一&#xff0c;在Java集合框架中以LinkedList的形式提供。本文将深入分析Java原生LinkedList的实现机制&#xff0c;并介绍我自定义实现的MyLinkedList&#xff0c;最后对比两者的设计差异与实现特点。 Java原生LinkedList解析 基本结构 Java的…

【深度学习】卷积神经网络(CNN):计算机视觉的革命性引擎

卷积神经网络&#xff08;CNN&#xff09;&#xff1a;计算机视觉的革命性引擎 一、算法背景&#xff1a;视觉智能的进化之路1.1 传统视觉处理的困境1.2 神经科学的启示 二、算法理论&#xff1a;CNN的核心架构2.1 基础组成单元卷积层&#xff1a;特征提取引擎池化层&#xff1…

使用@SpringJUnitConfig注解开发遇到的空指针问题

Spring测试中的版本陷阱&#xff1a;SpringJUnitConfig与JUnit版本兼容性深度解析 一个看似简单的空指针异常&#xff0c;背后可能隐藏着JUnit版本不匹配的“幽灵”。 一、SpringJUnitConfig&#xff1a;Spring与JUnit 5的桥梁 SpringJUnitConfig是Spring TestContext框架为**…

[2025CVPR]AdcSR:一种高效实世界图像超分辨率的对抗扩散压缩方法

目录 1. 背景与挑战 2. AdcSR模型概述 2.1 模型架构 2.2 训练策略 3. 公式与原理 4. 创新点 5. 实验与结果 5.1 实验设置 5.2 结果对比 5.3 消融实验 6. 结论 在计算机视觉领域&#xff0c;图像超分辨率&#xff08;Image Super-Resolution, ISR&#xff09;一直是一…

Go 语言中的字符串基本操作

这篇文章已经放到腾讯智能工作台的知识库啦&#xff0c;链接在这里&#xff1a;ima.copilot-Go 入门到入土。要是你有啥不懂的地方&#xff0c;就去知识库找 AI 聊一聊吧。 本篇将详细讲解 Go 语言中与字符串相关的操作。 1、rune 和 字符串长度 1、Go 函数语法约定 在开始…

数学建模会议笔记

看似优化模型 建立整数规划模型 用优化软件、启发式方法、精确方法求解 建立图论和组合优化模型用组合优化方法、启发式方法求解 建立博弈论模型 数据统计分析与可视化- 数据拟合、参数估计、插值、数据的标准化、去伪补全相关度分析、分类、聚类等 最优化理论和方法 线性规划…

学习昇腾开发的六天--ACL应用开发之运行第一个实例

1、下载一个实例&#xff0c;运行一个图像分类实例&#xff08;环境&#xff1a;Ubuntu22.04&#xff0c;硬件&#xff1a;昇腾310B1&#xff0c;加速模块&#xff1a;atlas 200i a2&#xff09; samples: CANN Samples - Gitee.com 目录结构如下&#xff1a; ├── data │…

可灵AI-快手公司自主研发的一款AI视频与图像生成工具

可灵AI是由快手公司自主研发的一款AI视频与图像生成工具&#xff0c;于2024年6月正式推出。以下是对其的详细介绍&#xff1a; 核心功能 AI视频生成&#xff1a; 文生视频&#xff1a;输入文字描述&#xff0c;AI可自动生成匹配的视频片段。图生视频&#xff1a;上传图片&…

创客匠人解析:存量时代创始人 IP 打造与免费流量池策略

在存量竞争的商业环境中&#xff0c;企业如何突破增长瓶颈&#xff1f;创客匠人结合新潮传媒创始人张继学的实战洞察&#xff0c;揭示 “品牌 IP” 双轮驱动下的免费流量池构建逻辑&#xff0c;为知识变现与创始人 IP 打造提供新思路。 一、存量时代的流量革命&#xff1a;从…

提升语义搜索效率:LangChain 与 Milvus 的混合搜索实战

我从不幻想人生能够毫无波折&#xff0c;但我期望遭遇困境之际&#xff0c;自身能够成为它的克星。 概述 LangChain与Milvus的结合构建了一套高效的语义搜索系统。LangChain负责处理多模态数据&#xff08;如文本、PDF等&#xff09;的嵌入生成与任务编排&#xff0c;Milvus作…

MySQL配置简单优化与读写测试

测试方法 先使用sysbench对默认配置的MySQL单节点进行压测&#xff0c;单表数据量为100万&#xff0c;数据库总数据量为2000万&#xff0c;每次压测300秒。 sysbench --db-drivermysql --time300 --threads10 --report-interval1 \--mysql-host192.168.0.10 --mysql-port3306…

猎板深耕透明 PCB,解锁电子设计新边界

在电子技术快速迭代的当下&#xff0c;猎板始终关注行业前沿&#xff0c;透明 PCB 作为极具创新性的技术&#xff0c;正在改变电子设备的设计与应用格局。​ 从传统的绿色、棕色 PCB 到如今的透明 PCB&#xff0c;其突破在于特殊基材与导电材料的运用&#xff0c;实现 85%-92%…

FLAML:快速轻量级自动机器学习框架

概述 FLAML&#xff08;Fast and Lightweight AutoML&#xff09;是微软开发的一个高效的自动机器学习&#xff08;AutoML&#xff09;框架。它专注于在有限的计算资源和时间约束下&#xff0c;自动化机器学习管道的构建过程&#xff0c;包括特征工程、模型选择、超参数调优等…