实现图片拖拽和缩小放大功能。
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...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...

ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...

【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道
文/法律实务观察组 在债务重组领域,专业机构的核心价值不仅在于减轻债务数字,更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明,合法债务优化需同步实现三重平衡: 法律刚性(债…...

阿里云Ubuntu 22.04 64位搭建Flask流程(亲测)
cd /home 进入home盘 安装虚拟环境: 1、安装virtualenv pip install virtualenv 2.创建新的虚拟环境: virtualenv myenv 3、激活虚拟环境(激活环境可以在当前环境下安装包) source myenv/bin/activate 此时,终端…...