实现图片拖拽和缩小放大功能。

1. 前言

不知道各位前端小伙伴蓝湖使用的多不多,反正我是经常在用,ui将原型图设计好后上传至蓝湖,前端开发人员就可以开始静态页面的的编写了。对于页面细节看的不是很清楚可以使用滚轮缩放后再拖拽查看,还是很方便的。于是就花了点时间研究了一下。今天分享给大家。

2. 实现

HTML

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

拖拽查看图片逻辑

java 复制代码
    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();
    }

滚轮缩放逻辑

javascript 复制代码
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全部代码

html 复制代码
<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>
相关推荐
张丹 新叶之扉3 小时前
图片预览 图片上传到服务器
服务器·前端·html5·js
A_cot13 天前
Vue.js:构建现代 Web 应用的强大框架
前端·javascript·vue.js·flutter·html·web·js
Liquor141920 天前
JavaScript知识点梳理及案例实践
开发语言·前端·javascript·python·css3·html5·js
fury_12320 天前
base64文本div中增加一个img标签,img标签实时渲染后端返回的base64数据成对应图片
java·服务器·前端·js
我命由我1234521 天前
CesiumJS 案例 P18:检测文本、删除所有文本、隐藏与显示文本、改变文本
前端·javascript·前端框架·html·css3·html5·js
海上彼尚21 天前
根据JSON绘制3D地区
前端·3d·js
我命由我1234522 天前
CesiumJS 案例 P19:添加矩形、监听鼠标左击、监听鼠标右击、监听鼠标移动
前端·javascript·前端框架·html·css3·html5·js
满分观测网友z23 天前
ExpandingCard扩展卡片
web·js
Hellc00724 天前
.eslintrc.js 的解释
js
我命由我1234524 天前
CesiumJS 案例 P16:标记平移、删除标记、隐藏与显示标记、标记颜色
前端·javascript·前端框架·html·css3·html5·js