纯 css 的 transform: scale() 不是真正放大镜,因它仅拉伸整图而无鼠标位置绑定、移动端不触发 hover、且放大后模糊;真放大镜需双图+background-position 动态映射,并处理加载时机、坐标对齐及移动端 touch 事件拦截。

为什么纯 CSS 的 transform: scale() 不是真正放大镜
它只是把整张图拉大后裁掉边缘,鼠标指哪儿、放大的区域就对应哪儿——这个绑定关系根本不存在。你 hover 时看到的“放大”,其实是图片中心被强行撑开,和鼠标位置无关;移动端连 hover 都不触发。更麻烦的是,transform: scale() 放大后必然模糊,因为浏览器是在渲染完缩略图后再拉伸像素,不是从高清源里取局部。
必须用双图 + background-position 动态映射
核心是两张图:img 显示小图(比如 400×300),data-large 属性存高清图地址(比如 1200×900)。放大容器不用 <img>,而用 div 设为 background-image,靠 background-position 移动“视口”。
- 监听
mousemove,用e.offsetX/e.offsetY获取鼠标在小图内的坐标(注意 IE 不支持,得 fallback 到getBoundingClientRect()手算) - 缩放倍数 =
largeWidth / smallWidth,比如 1200 / 400 = 3 -
background-position应设为-x * scale和-y * scale,才能让鼠标点始终居中显示 - 必须加边界限制:
Math.max(0, Math.min(largeWidth - viewWidth, -x * scale)),否则超出范围会留白或黑边
移动端 touch 事件要手动拦截
iOS Safari 和 Android Chrome 默认会把 touchmove 当成页面滚动,不处理就会卡顿或跳转。光加 touch-action: none 不够,还得在回调里立刻调用 e.preventDefault()。
- 给镜头容器(
.magnifier-lens)加touch-action: none - 在
touchmove回调第一行写e.preventDefault(),不能只在touchstart绑一次 - 用
touches[0]取第一个触点,别用changedTouches——它可能为空 - 高清图建议用
background-image而非<img>,iOS 下transform缩放容易模糊
最容易被忽略的加载时机问题
很多代码一加载就绑事件,但高清图还没下载完,naturalWidth 是 0,background-position 算出来全是 NaN,镜子里一片空白。
- 不能只等
img.onload:缓存命中时该事件根本不触发 - 必须检查
img.complete === true,再决定是否立即计算尺寸 - 稳妥做法:先监听
load,再手动判断complete,两者都覆盖 - 如果用
URL.createObjectURL()加载本地文件,绘制完成后记得调URL.revokeObjectURL(),否则内存泄漏
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











