实现图片拖拽和缩小放大功能。
1. 前言
不知道各位前端小伙伴蓝湖使用的多不多,反正我是经常在用,ui将原型图设计好后上传至蓝湖,前端开发人员就可以开始静态页面的的编写了。对于页面细节看的不是很清楚可以使用滚轮缩放后再拖拽查看,还是很方便的。于是就花了点时间研究了一下。今天分享给大家。
2. 实现
HTML
<div class="imgBox"><img style="width: 150px; height: 150px; padding: 10px" src="../../../images/HTTP工作原理.jpg" class="img-responsive" /><img style="width: 150px; height: 150px; padding: 10px" src="../../../images/HTTP报文结构.jpg" class="img-responsive" /></div><div id="outerdiv" style="position: fixed;top: 0;left: 0;background: rgba(0, 0, 0, 0.7);z-index: 2;width: 100%;height: 100%;display: none;"><img id="bigimg" src="" /></div>
js
拖拽查看图片逻辑
function imgDrag() {// 绑定 鼠标按下事件image.addEventListener("pointerdown", pointerdown);// 绑定 鼠标移动事件image.addEventListener("pointermove", pointermove);image.addEventListener("pointerup", function (e) {if (isPointerdown) {isPointerdown = false;}});image.addEventListener("pointercancel", function (e) {if (isPointerdown) {isPointerdown = false;}});}function pointerdown(e) {isPointerdown = true;console.log(e.pointerId)// 说明:Element.setPointerCapture()将特定元素指定为未来指针事件的捕获目标。指针的后续事件将以捕获元素为目标,直到捕获被释放。可以理解为:在窗口不是全屏情况下,我在拖动放大图片时即使鼠标移出可窗口之外,此时事件还是捕获在该放大图片上。image.setPointerCapture(e.pointerId);lastPointermove = {x: e.clientX,y: e.clientY,};}function pointermove(e) {if (isPointerdown) {const current1 = {x: e.clientX,y: e.clientY,};diff.x = current1.x - lastPointermove.x;diff.y = current1.y - lastPointermove.y;lastPointermove = {x: current1.x,y: current1.y,};x += diff.x;y += diff.y;image.style.transform = `translate3d(${x}px, ${y}px, 0) scale(${initScale})`;}e.preventDefault();}
滚轮缩放逻辑
function handleStopWheel(e) {let itemSizeChange = 1.1; //每一次滚动放大的倍数if (e.target.id == "bigimg") {// 说明:e.dataY如果大于0则表示鼠标向下滚动,反之则向上滚动,这里设计为向上滚动为缩小,向下滚动为放大if (e.deltaY < 0) {itemSizeChange = 1 / 1.1;}let _initScale = initScale * itemSizeChange;// 说明:在超过或低于临界值时,虽然让initScale等于maxZoom或minreduce,但是在后续的判断中放大图片的最终倍数并没有达到maxZoom或minreduce,而是跳过。if (_initScale > maxZoom) {initScale = maxZoom;} else if (_initScale < minreduce) {initScale = minreduce;} else {initScale = _initScale;}const origin = {x: (itemSizeChange - 1) * imgWidth * 0.5,y: (itemSizeChange - 1) * imgHeight * 0.5,};// 计算偏移量if (_initScale < maxZoom && _initScale > minreduce) {x -= (itemSizeChange - 1) * (e.clientX - x) - origin.x;y -= (itemSizeChange - 1) * (e.clientY - y) - origin.y;e.target.style.transform = `translate3d(${x}px, ${y}px, 0) scale(${initScale})`;}}// 阻止默认事件e.preventDefault();}
js全部代码
<script>/*** 实现图片点击放大、拖拽、滚轴滚动焦点缩放功能,相关参数、函数声明*/let imgWidth, imgHeight; // 图片点击放大初始尺寸参数let maxZoom = 4; //最大缩放倍数let minreduce = 0.5; // 最小缩放倍数let initScale = 1; //滚动缩放初始倍数,并不是图片点击放大的倍数let isPointerdown = false; //鼠标按下的标识//记录鼠标按下坐标和按下移动时坐标let lastPointermove = {x: 0,y: 0,};//移动过程从上一个坐标到下一个坐标之间的差值let diff = {x: 0,y: 0,};//图片放大后左上角的坐标,主要结合diff参数用于鼠标焦点缩放时图片偏移坐标let x = 0;let y = 0;// 记录节点const allImg = document.querySelectorAll(".imgBox img");const outerdiv = document.querySelector("#outerdiv");const image = outerdiv.querySelector("#bigimg");window.onload = function () {allImg.forEach((item) => {item.addEventListener("click", (e) => {const that = e.target;image.style.transform = "scale(1)";//图片放大展示函数调用imgShow(that);// 监听鼠标滚动事件window.addEventListener("wheel", handleStopWheel, {passive: false,});// 拖转事件调用imgDrag();});});};function imgShow(that) {let src = that.getAttribute("src");image.setAttribute("src", src);// 设置尺寸和调整比例let windowW = document.documentElement.clientWidth;let windowH = document.documentElement.clientHeight;let realWidth = image.naturalWidth; //获取图片的原始宽度let realHeight = image.naturalHeight; //获取图片的原始高度let outsideScale = 0.8;let belowScale = 1.4;let realRatio = realWidth / realHeight;let windowRatio = windowW / windowH;// 说明:下面是我自己的一些判断逻辑,大致意思就是图片的真实尺寸大于屏幕尺寸则使用屏幕尺寸,如果小于屏幕尺寸就使用自己本身的尺寸;并根据大于或者小于的比例对图片的尺寸进一步调整。coder可以根据自己的要求进行修改。if (realRatio >= windowRatio) {if (realWidth > windowW) {imgWidth = windowH * outsideScale;imgHeight = (imgWidth / realWidth) * realHeight;} else {if (realWidth * belowScale < windowW) {imgWidth = realWidth * (belowScale - 0.2);imgHeight = (imgWidth / realWidth) * realHeight;} else {imgWidth = realWidth;imgHeight = realHeight;}}} else {if (realHeight > windowH) {imgHeight = windowH * outsideScale;imgWidth = (imgHeight / realHeight) * realWidth;} else {if (realHeight * belowScale < windowW) {imgHeight = realHeight * (belowScale - 0.2);imgWidth = (imgHeight / realHeight) * realWidth;} else {imgWidth = realWidth;imgHeight = realHeight;}}}//设置放大图片的尺寸、偏移量并展示image.style.width = imgWidth + "px";image.style.height = imgHeight + "px";x = (windowW - imgWidth) * 0.5;y = (windowH - imgHeight) * 0.5;image.style.transform = `translate3d(${x}px, ${y}px, 0)`;outerdiv.style.display = "block";// 点击蒙版及外面区域放大图片关闭outerdiv.onclick = () => {outerdiv.style.display = "none";initScale = 1;window.removeEventListener("wheel", handleStopWheel);};// 阻止事件冒泡image.onclick = (e) => {e.stopPropagation();};}function handleStopWheel(e) {let itemSizeChange = 1.1; //每一次滚动放大的倍数if (e.target.id == "bigimg") {// 说明:e.dataY如果大于0则表示鼠标向下滚动,反之则向上滚动,这里设计为向上滚动为缩小,向下滚动为放大if (e.deltaY < 0) {itemSizeChange = 1 / 1.1;}let _initScale = initScale * itemSizeChange;// 说明:在超过或低于临界值时,虽然让initScale等于maxZoom或minreduce,但是在后续的判断中放大图片的最终倍数并没有达到maxZoom或minreduce,而是跳过。if (_initScale > maxZoom) {initScale = maxZoom;} else if (_initScale < minreduce) {initScale = minreduce;} else {initScale = _initScale;}const origin = {x: (itemSizeChange - 1) * imgWidth * 0.5,y: (itemSizeChange - 1) * imgHeight * 0.5,};// 计算偏移量if (_initScale < maxZoom && _initScale > minreduce) {x -= (itemSizeChange - 1) * (e.clientX - x) - origin.x;y -= (itemSizeChange - 1) * (e.clientY - y) - origin.y;e.target.style.transform = `translate3d(${x}px, ${y}px, 0) scale(${initScale})`;}}// 阻止默认事件e.preventDefault();}function imgDrag() {// 绑定 鼠标按下事件image.addEventListener("pointerdown", pointerdown);// 绑定 鼠标移动事件image.addEventListener("pointermove", pointermove);image.addEventListener("pointerup", function (e) {if (isPointerdown) {isPointerdown = false;}});image.addEventListener("pointercancel", function (e) {if (isPointerdown) {isPointerdown = false;}});}function pointerdown(e) {isPointerdown = true;console.log(e.pointerId)// 说明:Element.setPointerCapture()将特定元素指定为未来指针事件的捕获目标。指针的后续事件将以捕获元素为目标,直到捕获被释放。可以理解为:在窗口不是全屏情况下,我在拖动放大图片时即使鼠标移出可窗口之外,此时事件还是捕获在该放大图片上。image.setPointerCapture(e.pointerId);lastPointermove = {x: e.clientX,y: e.clientY,};}function pointermove(e) {if (isPointerdown) {const current1 = {x: e.clientX,y: e.clientY,};diff.x = current1.x - lastPointermove.x;diff.y = current1.y - lastPointermove.y;lastPointermove = {x: current1.x,y: current1.y,};x += diff.x;y += diff.y;image.style.transform = `translate3d(${x}px, ${y}px, 0) scale(${initScale})`;}e.preventDefault();}</script>
相关文章:
实现图片拖拽和缩小放大功能。
1. 前言 不知道各位前端小伙伴蓝湖使用的多不多,反正我是经常在用,ui将原型图设计好后上传至蓝湖,前端开发人员就可以开始静态页面的的编写了。对于页面细节看的不是很清楚可以使用滚轮缩放后再拖拽查看,还是很方便的。于是就花了…...
昇思25天学习打卡营第18天|munger85
DCGAN生成漫画头像 首先肯定是下载训练数据,而这些训练数据就是一些卡通头像。后来我们会看到这个具体的头像 就像其他的数据集目录一样,它是由一些目录和这个目录下面的文件组成的数据集。 有相当多的图片。所以可以训练出来比较好的效果。 图片的处理…...
nginx配置文件说明
Nginx的配置文件说明 Nginx配置文件的主要配置块可以分为三个部分:全局配置块(events和http块),events块和http块。这三个部分共同定义了Nginx服务器的整体行为和处理HTTP请求的方式。 全局配置块: 包含了影响Nginx服…...
用不同的url头利用Python访问一个网站,把返回的东西保存为txt文件
这个需要调用requests模块(相当于c的头文件) import requests 还需要一个User-Agent头(这个意思就是告诉python用的什么系统和浏览器) Google Chrome(Windows): Mozilla/5.0 (Windows NT 10.0; Win64; x64…...
一文掌握Prometheus实现页面登录认证并集成grafana
一、接入方式 以保护Web站点的访问控制,如HTTP 服务器配置中实现安全的加密通信和身份验证,保护 Web 应用程序和用户数据的安全性。 1.1 加密密码 通过httpd-tools工具包来进行Web站点加密 yum install -y httpd-tools方式一:通过htpasswd生…...
欢迎来到 Mint Expedition:Web3 和 NFT 的新时代开始
7 月 15 日,Mint Expedition 正式开启,作为 Mint 生态系统的旗舰项目,将彻底变革 Web3 和 NFT 去中心化应用! Mint Expedition 是 Mint 的最新航程,延续了 Mint Forest 的成功。Mint Forest 吸引了超过 41.4 万独立用…...
针对环境构图的全局一致性扫描点云数据对齐(Graph SLAM)
本算法是一个经典的,针对SLAM(simultaneous localization and mapping 即时定位与地图构建)问题而提出的算法。该算法的提出者是Feng Lu和Evangelos Milios,他们在本算法中开创了通过全局优化方程组以减少约束引入的误差来进一步优…...
Matlab学习笔记01 - 基本数据类型
Matlab学习笔记01 - 基本数据类型 1、数据类型转换2、矩阵2.1 访问单个矩阵元素2.2 访问多个矩阵元素2.3 矩阵转置 3、字符与字符串4、数值与字符串5、元胞数组 1、数据类型转换 十进制转十六进制字符串‘FF’ >> hex2dec(3ff)ans 1023十进制转十六进制字符串 >>…...
基于重要抽样的主动学习不平衡分类方法ALIS
这篇论文讨论了数据分布不平衡对分类器性能造成的影响,并提出了一种新的有效解决方案 - 主动学习框架ALIS。 1、数据分布不平衡会影响分类器的学习性能。现有的方法主要集中在过采样少数类或欠采样多数类,但往往只采用单一的采样技术,无法有效解决严重的类别不平衡问题。 2、论…...
Python爬虫(基本流程)
1. 确定目标和范围 明确需求:确定你需要从哪些网站抓取哪些数据。合法性:检查目标网站的robots.txt文件,了解哪些内容可以被抓取。数据范围:确定爬取数据的起始和结束点,比如时间范围、页面数量等。 2. 选择合适的工…...
primeflex教学笔记20240720, FastAPI+Vue3+PrimeVue前后端分离开发
练习 先实现基本的页面结构: 代码如下: <template><div class"flex p-3 bg-gray-100 gap-3"><div class"w-20rem h-12rem bg-indigo-200 flex justify-content-center align-items-center text-white text-5xl">…...
移动设备安全革命:应对威胁与解决方案
移动设备已成为我们日常工作和家庭生活中不可或缺的工具,然而,对于它们安全性的关注和投资仍然远远不够。本文深入分析了移动设备安全的发展轨迹、目前面临的威胁态势,以及业界对于这些安全漏洞响应迟缓的深层原因。文中还探讨了人们在心理层…...
【C语言】 链表实现学生管理系统(堆区开辟空间)
总体思路都能写出来,问题是感觉稍微比之前的麻烦一些,在刚开始创建结构体的时候,并没有去按照链表的思路去写,导致写成了顺序表,后面就一直纠结空间怎么开辟。 链表是由一个头节点和其它申请出来的小节点连起来的&…...
STM32实战篇:按键(外部输入信号)触发中断
功能要求 将两个按键分别与引脚PA0、PA1相连接,通过按键按下,能够触发中断响应程序(不需明确功能)。 代码流程如下: 实现代码 #include "stm32f10x.h" // Device headerint main() {//开…...
Android SurfaceView 组件介绍,挖洞原理详解
文章目录 组件介绍基本概念关键特性使用场景 SurfaceHolder介绍主要功能使用示例 SurfaceView 挖洞原理工作机制 使用SurfaceView展示图片示例创建一个自定义的 SurfaceView类在 Activity 中使用 ImageSurfaceView注意事项效果展示 组件介绍 在 Android 开发中,Sur…...
day2加餐 Go 接口型函数的使用场景
文章目录 问题价值使用场景其他语言类似特性 问题 在 动手写分布式缓存 - GeeCache day2 单机并发缓存 这篇文章中,有一个接口型函数的实现: // A Getter loads data for a key. type Getter interface {Get(key string) ([]byte, error) }// A Getter…...
摄像头 RN6752v1 视频采集卡
摄像头 AHD倒车摄像头比较好,AHD英文全名Analog High Definition,即模拟高清,拥有比较好的分辨率与画面质感。 RN6752v1 GQW AKKY2 usb 采集卡 FHD(1080p)、HD(720p)和D1(480i&am…...
记录vivado自带IP iBert眼图近端回环
记录利用vivado自带IP核工具测试信号质量 ibert是测试眼图的工具,在使用的时候并不用改太多的内容,只需要注意参考时钟及所需要的引脚即可。由于条件的限制,并没有使用光纤和电缆进行连接进行外部回环,仅使用内部回环做测试&…...
js | Core
http://dmitrysoshnikov.com/ecmascript/javascript-the-core/ Object 是什么? 属性[[prototype]]对象。 例如,下面的,son是对象,foo不是对象。打印出来的son,能看到有一个prototype 对象。 prototype vs _proto_ v…...
Log4J reminder
Java JNDI and Log injection https://docs.oracle.com/javase/jndi/tutorial/ See also https://telegra.ph/Log4J-Vulnerability-Explained-07-21...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...
MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...
【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅
目录 前言 操作系统与驱动程序 是什么,为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中,我们在使用电子设备时,我们所输入执行的每一条指令最终大多都会作用到硬件上,比如下载一款软件最终会下载到硬盘上&am…...
