当前位置: 首页 > news >正文

js函数预览图片:支持鼠标和手势拖拽缩放

对之前的方式改进:原生js实现图片预览控件,支持丝滑拖拽,滚轮放缩,放缩聚焦_js图片预览-CSDN博客

/*** 图片预览函数,调用后自动预览图片* @param {图片地址} imgurl*/
function openImagePreview(imgurl) {if (!imgurl) return;const max = 30;//放缩原图倍数const scale = 0.1;//滚轮一下缩放的变化比例 越大放缩越快const box = document.createElement("div");box.style.cssText = "position: fixed;top:0px;left:0px;z-index: 10000;background-color: rgba(0,0, 0, 0.3);width:100%;height:100%;overflow: hidden;cursor: grab;";const img = document.createElement("img");img.style.cssText = "position: absolute;object-fit: contain;user-select: none;-webkit-user-drag: none;user-select: none;-moz-user-select: none;-webkit-user-select: none;-ms-user-select: none;";img.src = imgurl;img.title = "预览";const close = document.createElement("div");close.innerHTML = `<svg aria-hidden="true" role="img" font-size="20"  width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 16 16"><g fill="none" fill-rule="evenodd"><path d="M0 0h16v16H0z"></path><path fill="currentColor" d="M13.303 2.697a.5.5 0 010 .707L8.707 8l4.596 4.596a.5.5 0 01-.707.707L8 8.707l-4.596 4.596a.5.5 0 01-.707-.707L7.293 8 2.697 3.404a.5.5 0 01.707-.707L8 7.293l4.596-4.596a.5.5 0 01.707 0z"></path></g></svg>`;close.style.cssText = "position: absolute;top:20px;right:20px;align-items: center;color:white;display: flex;justify-content: center;background: rgba(29,29,37,0.4);border-radius: 50%;width:30px;height:30px;";close.onclick = () => {document.body.removeChild(box);}box.append(img);box.append(close);document.body.append(box);img.onload = function () {const imgRatio = img.naturalWidth / img.naturalHeight; //图片横纵比const boxRatio = box.clientWidth / box.clientHeight;   //容器横纵比if (imgRatio > boxRatio) {const scale = box.clientWidth / img.naturalWidth;img.style.width = box.clientWidth + "px"; //长度填充img.style.height = img.naturalHeight * scale + "px"; //高度自适应img.style.top = Math.ceil((box.clientHeight - img.clientHeight) / 2) + "px";//位置居中} else {const scale = box.clientHeight / img.naturalHeight;img.style.height = box.clientHeight + "px";//高度填充img.style.width = img.naturalWidth * scale + "px";//长度自适应img.style.left = Math.ceil((box.clientWidth - img.clientWidth) / 2) + "px";//位置居中}const download = document.createElement("div");download.innerHTML = `<svg style="width: 1em;height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024"  ><path d="M511.3 856.9c-11.3 0-20.4-9.1-20.4-20.4V87c0-11.3 9.1-20.4 20.4-20.4s20.4 9.2 20.4 20.4v749.5c0.1 11.2-9.1 20.4-20.4 20.4z" fill="#FFFFFF" ></path><path d="M511.3 857.3c-20.5 0-39.7-8-54.2-22.4L187.3 565c-8-8-8-20.9 0-28.9s20.9-8 28.9 0L486.1 806c6.7 6.7 15.7 10.5 25.2 10.5s18.5-3.7 25.2-10.5l269.9-269.9c8-8 20.9-8 28.9 0s8 20.9 0 28.9L565.5 834.9c-14.5 14.5-33.7 22.4-54.2 22.4zM170.8 961.2c-11 0-20.1-8.8-20.4-19.9-0.3-11.3 8.6-20.7 19.9-21l681-18.1h0.6c11 0 20.1 8.8 20.4 19.9 0.3 11.3-8.6 20.7-19.9 21l-681 18.1h-0.6z" fill="#FFFFFF" ></path></svg>`;download.style.cssText = "position: absolute;top:20px;right:60px;align-items: center;color:white;display: flex;justify-content: center;background: rgba(29,29,37,0.4);border-radius: 50%;width:30px;height:30px;";download.onclick = () => {let fileName = imgurl;let downloadUrl = imgurl;try {const regex = /([^/\\?&]+(?:\.[a-zA-Z0-9\u4e00-\u9fa5_-]+))(?:[?#]|$)/;const match = imgurl.match(regex);fileName = match ? match[0] : null;if (!fileName) {fileName = new Date().getTime() + ".png";}} catch (e) {}if (fileName.trim().toLowerCase().endsWith(".svg")) {fileName = fileName.substring(0, fileName.lastIndexOf(".svg")) + ".png";// 创建一个 canvas 元素const canvas = document.createElement('canvas');const ctx = canvas.getContext('2d');canvas.width = img.clientWidth;canvas.height = img.clientHeight;ctx.drawImage(img, 0, 0);downloadUrl = canvas.toDataURL('image/png');}let link = document.createElement('a')link.style.display = 'none'link.href = downloadUrllink.target = "_blank";link.setAttribute('download', fileName);document.body.appendChild(link)link.click()document.body.removeChild(link) //下载完成移除元素window.URL.revokeObjectURL(downloadUrl) //释放掉blob对象}box.append(download);};const getRange = (actual, limita, limitb) => {if (actual < -limita) {return -limita;} else if (actual > limitb) {return limitb;}return actual;}const drag = {status: false, lastX: null, lastY: null}const dragStart = (x, y) => {if (drag === true) return;drag.status = truedrag.lastX = xdrag.lastY = y}const dragMove = (x, y) => {if (drag.status) {let mx = x - drag.lastXlet my = y - drag.lastYdrag.lastX = xdrag.lastY = ylet top = img.offsetTop + mylet left = img.offsetLeft + mximg.style.left = getRange(left, img.clientWidth - 10, box.clientWidth - 10) + 'px';img.style.top = getRange(top, img.clientHeight - 10, box.clientHeight - 10) + "px";}}const dragEnd = () => {drag.status = falsedrag.lastX = nulldrag.lastY = null}const zoom = {status: false,lastDistance: null,lastCenter: null,}const getCenter = (x1, y1, x2, y2) => {return {x: (x1 + x2) / 2, y: (y1 + y2) / 2}}const getDistance = (x1, y1, x2, y2) => {const dx = x2 - x1;const dy = y2 - y1;return Math.sqrt(dx * dx + dy * dy); // 返回距离}const zoomStart = (x1, y1, x2, y2) => {zoom.lastDistance = getDistance(x1, y1, x2, y2);zoom.center = getCenter(x1, y1, x2, y2)dragStart(zoom.center.x, zoom.center.y);}const zoomCore = (isChangeBig, center_x, center_y, changeScale) => {const top_d = center_y - img.offsetTop;const left_d = center_x - img.offsetLeft;let modifyHeight = img.clientHeight * changeScale;let modifyWidth = img.clientWidth * changeScale;if (isChangeBig && modifyHeight > img.naturalHeight * max) return;if (!isChangeBig && modifyHeight * max < img.naturalHeight) return;img.style.height = modifyHeight + "px";img.style.width = modifyWidth + "px";img.style.top = (center_y - top_d * changeScale) + "px";img.style.left = (center_x - left_d * changeScale) + "px";}const zoomMove = (x1, y1, x2, y2) => {let newDistance = getDistance(x1, y1, x2, y2);let center = getCenter(x1, y1, x2, y2)if (Math.abs(newDistance - zoom.lastDistance) > 0.1) {zoomCore(zoom.lastDistance < newDistance, center.x, center.y, newDistance / zoom.lastDistance);}zoom.lastDistance = newDistance;}const zoomEnd = () => {zoom.lastDistance = null;zoom.center = null;dragEnd();}box.ontouchstart = (event) => {if (event.touches.length === 1) {dragStart(event.touches[0].pageX, event.touches[0].pageY);} else if (event.touches.length === 2) {zoomStart(event.touches[0].pageX, event.touches[0].pageY, event.touches[1].pageX, event.touches[1].pageY)}box.ontouchmove = (e) => {if (event.touches.length === 1) {dragMove(e.touches[0].pageX, e.touches[0].pageY);} else if (e.touches.length === 2) {zoomMove(e.touches[0].pageX, e.touches[0].pageY, e.touches[1].pageX, e.touches[1].pageY)}}box.ontouchend = () => {zoomEnd();box.ontouchmove = null;box.ontouchend = null;}}box.onmousedown = (event) => {document.body.style.userSelect = 'none';if (event.button === 0) {document.onmousemove = (event) => {dragMove(event.clientX, event.clientY);}document.onmouseup = (event) => {document.body.style.userSelect = '';if (event.button === 0) {dragEnd();document.onmousemove = nulldocument.onmouseup = null}}dragStart(event.clientX, event.clientY);}}box.onwheel = (event) => {event.preventDefault(); //关闭默认事件zoomCore(event.deltaY < 0, event.clientX, event.clientY, event.deltaY > 0 ? (1 - scale) : (1 + scale));}
}

http://www.lryc.cn/news/515954.html

相关文章:

  • 用QT实现 端口扫描工具1
  • 设计模式 结构型 适配器模式(Adapter Pattern)与 常见技术框架应用 解析
  • vue 项目集成 electron 和 electron 打包及环境配置
  • vscode如何离线安装插件
  • 计算机网络常见面试题及解答
  • 举例说明AI模型怎么聚类,最后神经网络怎么保存
  • HarmonyOS NEXT应用开发实战(一):边学边玩,从零开发一款影视APP
  • STM32G0B1 can Error_Handler 解决方法
  • 使用 `llama_index` 构建智能问答系统:多种文档切片方法的评估
  • 【大模型】7 天 AI 大模型学习
  • 软件工程大复习之(四)——面向对象与UML
  • 【Linux】shell命令
  • ValuesRAG:以检索增强情境学习强化文化对齐
  • 【机器学习篇】交通革命:机器学习如何引领未来的道路创新
  • DeepSeek-V3 通俗详解:从诞生到优势,以及与 GPT-4o 的对比
  • 把vue项目或者vue组件发布成npm包或者打包成lib库文件本地使用
  • 【STC库函数】Compare比较器的使用
  • 单片机-独立按键矩阵按键实验
  • 若要把普通表转成分区表,就需要先新建分区表,然后把普通表中的数据导入新建分区表。 具体怎么导入?
  • XXX公司面试真题
  • 第一节:电路连接【51单片机+A4988+步进电机教程】
  • 机器学习算法深度解析:以支持向量机(SVM)为例的实践应用
  • 解决Postman一直在转圈加载无法打开问题的方法
  • 利用 LangChain 构建对话式 AI 应用
  • 力扣--34.在排序数组中查找元素的第一个和最后一个位置
  • 【Java回顾】Day2 正则表达式----异常处理
  • 【SpringBoot】当 @PathVariable 遇到 /,如何处理
  • 【FlutterDart】页面切换 PageView PageController(9 /100)
  • Backend - C# 的日志 NLog日志
  • Flask是什么?深入解析 Flask 的设计与应用实践