1. 前言
- 实现图片点击放大、拖拽、滚轴滚动焦点缩放功能
- 放了完整,coder可以复制去看效果,不要忘记替换代码中的图片路径
2. 代码
2.1 html+js+css完成代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <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> <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> </body> </html>
复制
2.2 函数分析
-
imgShow
函数:- 主要功能:显示放大后的图片,为蒙版添加一个点击隐藏放大图片的事件,给放大图片添加点击阻止冒泡事件;
- 得到
x
、y
的值是放大图片在屏幕中高度
和宽度
留下空白一半的值。- 原理:屏幕宽高尺寸减去图片宽高尺寸得到值之后取一半;
- 可以利用这个值使用
transform
属性让图片在屏幕中间。
-
handleStopWheel
函数- 主要功能:鼠标滚动缩放已经放大的图片,同时得到偏移
x
、y
值,实现焦点缩放; e.deltaY
大于0则表示鼠标滚轴向下滚动,反之则向上滚动,这里设计为向上滚动为缩小,向下滚动为放大;
复制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})`; } (itemSizeChange - 1)
有两个值:0.1
和-0.09090990...
也就是放大一次是10%,缩小一次大约9%;origin
对象得到值,为一次缩放时,放大图片在原有的基础之上增加或者减少的值
的一半(e.clientX - x)
,x
为第一次缩放时imgShow
函数中得到的值;e.clientX
为鼠标所在位置的x轴坐标值- 得到的结果为:放大图片缩放之前鼠标距离放大图片左侧边缘的间距;
- 分析稍微有点乱,下面是一个举例:
- 设屏幕大小为200x200,放大图片
width:100px,height:100px
,鼠标位于则120x120,做一次放大操作 - 放大图片打开:
x = (200-100)*0.5, y = 50
; origin = {x: 0.1 * 100 * 0.5, y: 5}
;(itemSizeChange - 1) * (e.clientX - x) - origin.x = 0.1 * ( 120 - 50 ) - 5 = 2
;(itemSizeChange - 1) * (e.clientY - y) - origin.y = 2
;- 计算需要的偏移量为
x = 50 - 2
;y = 48
,从原来的偏移(50,50),变为了(48,48)放大10%
- 设屏幕大小为200x200,放大图片
- 主要功能:鼠标滚动缩放已经放大的图片,同时得到偏移
-
imgDrag
函数:- 主要功能:实现拖拽功能,在鼠标按下时(
pointerdown
函数)指定为未来指针事件的捕获目标,并且记录最初的鼠标坐标;鼠标移动时(pointermove
函数)计算鼠标移动后坐标与上一次鼠标坐标的差值,得到放大图片最终需要偏移的值。
- 主要功能:实现拖拽功能,在鼠标按下时(
3.效果参考
4. 参考链接
- https://juejin.cn/post/7009892447211749406
5. 写在最后
如果有所帮助,希望能够点赞、收藏支持,谢谢喽。