在测试的过程中,发现页面滚动后,会出现遮罩定位错误的情况,原来是因为初始化时,我们固定死了小图框的位置信息(存放在 this.imgRectNow ),导致 handMove 事件中的移动数据计算错误。
解决这个问题有两种方案:
监听 scroll 事件,更新 this.imgRectNow;
在 handMove 事件中更新 this.imgRectNow。
这里选择了第二种。
handMove(e) { // 动态获取小图的位置(或者监听 scroll ) let imgRectNow = this.imgObj.getBoundingClientRect(); let objX = e.clientX - imgRectNow.left; let objY = e.clientY - imgRectNow.top; // 原 handMove 事件剩余内容 ... },
综合以上,我们已经实现了一个完美的图片放大镜功能。最终的 js 如下所示:
data() { return { imgObj: {}, moveLeft: 0, moveTop: 0, transformMask:`translate(0px, 0px)`, showMagnifier:false, showMask:false, init: false, }; }, computed: { bigWidth(){ return this.configs.scale * this.configs.width; }, bigHeight(){ return this.configs.scale * this.configs.height; } }, methods: { handMove(e) { // 动态获取小图的位置(或者监听 scroll ) let imgRectNow = this.imgObj.getBoundingClientRect(); let objX = e.clientX - imgRectNow.left; let objY = e.clientY - imgRectNow.top; // 计算初始的遮罩左上角的坐标 let maskX = objX - this.configs.maskWidth / 2; let maskY = objY - this.configs.maskHeight / 2; // 判断是否超出界限,并纠正 maskY = maskY < 0 ? 0 : maskY; maskX = maskX < 0 ? 0 : maskX; if(maskY + this.configs.maskHeight >= imgRectNow.height) { maskY = imgRectNow.height - this.configs.maskHeight; } if(maskX + this.configs.maskWidth >= imgRectNow.width) { maskX = imgRectNow.width - this.configs.maskWidth; } // 遮罩移动 this.transformMask = `translate(${maskX}px, ${maskY}px)`; // 背景图移动 this.moveLeft = - maskX * this.configs.scale + "px"; this.moveTop = - maskY * this.configs.scale + "px"; }, handOut() { this.showMagnifier = false; this.showMask = false; }, handOver() { if (!this.init) { this.init = true; this.imgObj = this.$el.getElementsByClassName('small-box')[0]; } this.showMagnifier = true; this.showMask = true; } }
使用方法
本示例中的固定参数:小图框:420 * 420 。
程序可接受参数:
// 小图地址 src: { type: String, }, // 大图地址 bigSrc: { type: String, }, // 配置项 configs: { type: Object, default() { return { width:420,//放大区域 height:420,//放大区域 maskWidth:210,//遮罩 maskHeight:210,//遮罩 maskColor:'rgba(25,122,255,0.5)',//遮罩样式 maskOpacity:0.6, scale:2,//放大比例 }; } }
文中图 2 是一张长图,小图的最大边不超过 836px(二倍图) ,大图为了视觉效果,分辨率尽量高点,程序会根据配置项自动设置对应的 height , width ,长图与宽图的效果对比可参考图3。
配置项可根据应用场景自行设置,本文示例的配置项是 2 倍放大,效果可参考图 4,四倍放大效果可参考图 5。
总结
其实图片放大镜的实现思路没有那么复杂,核心点有两点:
小图、大图的定位,遮罩和放大区域的创建方法
放大镜的原理理解,并用代码实现 DOM 的移动等。
本文顺着这个思路,做了一个简单的实现,还有一些优化的空间,欢迎各位大佬在评论区讨论。虽然代码看起来不是非常优雅,但是足够明了,感兴趣的同学可以自己尝试一下。