基于 Vue 的商品主图放大镜方案
实现原理
放大镜的原理用一句话概括,就是根据小图上的鼠标位置去定位大图。
图1 原理图(以2倍放大为例)
相信原理图已经画的很明白了, 图中,左侧框是小图框,其蓝色区域为图片遮罩层(需放大区域),右侧框是整个大图目前所在区域,其蓝色区域是放大区域,设置超出隐藏,就实现了放大遮罩区域的效果。
显然,两块蓝色区域存在着某种对应关系,即遮罩的左上角位置(相对于小图,以下称 X 坐标)和放大区域(相对于大图)的左上角位置是成比例的,即放大倍数。计算出 X 坐标后,适当调整背景图的位置,使大图向反方向移动 scale 倍的 X 坐标即可。
X 坐标为(maskX,maskY),以计算 maskX 为例:
鼠标移动中会产生 e.clientX ,标识鼠标与浏览器左侧的距离,小图与浏览器左侧的距离是 left ,由于遮罩始终是一个以鼠标为中心的正方形,所以:
maskX = e.clientX - left - mask/2
同理,
maskY = e.clientY - top - mask/2
大图的对应样式设置为:
{left: - maskX * scale + 'px';top: - maskY * scale + 'px';
}
复制代码
效果演示
图2 长图展示
图3 宽图展示
图4 两倍放大效果图
图5 四倍放大效果图
核心代码
HTML
一般放大镜实现的是 1:1 等宽等高的正方形图片,这里兼容了其他比例的图片,设置图片为垂直居中对齐,包括小图,大图。如果小图不够充满整个小图框,余留下的空白部分也可以有放大效果,只不过放大结果依然是空白。 这样只需计算背景图的移动距离,不用过多的关注图片定位问题。
<template><div class="magnifier"><!-- 小图 --><div class="small-box" @mouseover="handOver" @mousemove="handMove" @mouseout="handOut"><img class="smallPic" :src="`${src}?x-oss-process=image/resize,l_836`" /><div class="magnifier-zoom" v-show="showMask":style="{background: configs.maskColor,height: configs.maskWidth + 'px',width: configs.maskHeight + 'px', opacity: configs.maskOpacity, transform: transformMask}"></div></div><!-- 大图, 注意误差 --><div class="magnifier-layer" v-show="showMagnifier":style="{ width: configs.width + 'px', height: configs.height + 'px', left: configs.width + 20 + 'px' }"><div class="big-box":style="{ width: bigWidth + 'px',height: bigHeight + 'px',left: moveLeft,top: moveTop}"><div class="big-box-img":style="{ width: bigWidth - 2 + 'px', height: bigHeight - 2 + 'px' }"><img:src="bigSrc":style="{ maxWidth: bigWidth - 2 + 'px', maxHeight: bigHeight -2 + 'px' }"/></div></div></div></div>
</template>
复制代码
JS
这里主要有三个事件函数。
- handOver:鼠标进入到小图框上的事件,此时显示遮罩和放大区域,并计算小图框的位置信息。
handOver() {// 计算小图框在浏览器中的位置this.imgObj = this.$el.getElementsByClassName('small-box')[0];this.imgRectNow = this.imgObj.getBoundingClientRect();this.showMagnifier = true;this.showMask = true;
}复制代码
- handMove:鼠标在小图上的移动事件,此事件发生在 handOver 之后,计算数据,移动遮罩以及背景图;
handMove(e) {// 计算初始的遮罩左上角的坐标let objX = e.clientX - this.imgRectNow.left;let objY = e.clientY - this.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 >= this.imgRectNow.height) {maskY = this.imgRectNow.height - this.configs.maskHeight;}if(maskX + this.configs.maskWidth >= this.imgRectNow.width) {maskX = this.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:鼠标离开小图事件,此时无放大镜效果,隐藏遮罩和放大区域。
handOut() {this.showMagnifier = false;this.showMask = false;
}
复制代码
以上三个事件基本上就实现了图片的放大镜功能。
但仔细看,你会发现每次移入小图框都会触发一次 handOver 事件,并且计算一次小图框 DOM (imgObj) 。
为了优化此问题,可以用 init 标识是否是页面加载后首次触发 handOver 事件,如果是初始化就计算imgObj 信息,否则不计算。
handOver() {if (!this.init) {this.init = true;// 原 handOver 事件...} this.showMagnifier = true;this.showMask = true;
},复制代码
在测试的过程中,发现页面滚动后,会出现遮罩定位错误的情况,原来是因为初始化时,我们固定死了小图框的位置信息(存放在 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 的移动等。
本文顺着这个思路,做了一个简单的实现,还有一些优化的空间,欢迎各位大佬在评论区讨论。虽然代码看起来不是非常优雅,但是足够明了,感兴趣的同学可以自己尝试一下。
作者:政采云前端团队
链接:https://juejin.im/post/5d8235565188256bbe57dc84
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
基于 Vue 的商品主图放大镜方案相关推荐
- 【每日一练】原生js仿淘宝主图放大镜功能,附学习源码
在我们的项目中,经常会遇到各种功能效果的实现,对于每一项功能的实现方式,都有很多种,这些实现方式没有好坏之分,只有适合与否,但是我个人建议,如果项目急就选择自己擅长的方式实现,比较完成工作更加重要嘛. ...
- 第37课 thinkphp5添加商品基本信息及通过前置钩子上传商品主图 模型事件(勾子函数)...
目录 手册地址: before_insert(新增之前的操作) 要实现的功能 思路 触发条件: 1. 控制器里必须要调用模型的save()方式保存数据,用insert()触发不了勾子函数的 2. 模型 ...
- php上传商品信息并显示,第37课 thinkphp5添加商品基本信息及通过前置钩子上传商品主图 模型事件(勾子函数)...
[TOC] 手册地址: before_insert(新增之前的操作) 要实现的功能 上传原图片,在新增数据之前生成三张缩略图片,然后再插入数据 添加商品基本信息及通过后置钩子上传商品主图 思路 控制器 ...
- 教你一键采集天猫商品主图视频的方法及步骤
多个天猫商品的主图视频要怎么一键采集保存到电脑上呢?看看大家是如何用"视频下载高手"软件来省时间采集的,现在跟小编一起看下操作步骤吧. 已下载的商品主图视频展示 准备所需要的软件 ...
- 教您如何批量采集1688商城多个商品主图和详情页并统一保存
下面先让大伙浏览一组,就是运用载图助手电商图片及视频采集专用工具,所下载好的一些真实商品主图原图,和详情图以及视频等.详情操作一会儿给一一给大家介绍哈. 一.软件的智能分类保存功能 1.所下载好的文件 ...
- 京东商品主图怎么保存?如何正确的保存到原图?
各位京东商家们,如果您在京东商城看到了好看的京东商品图片,是不是有想把它保存起来的冲动呢?告诉您是可以把图片保存起来的哦,更可以用到自己的京东店铺上去的,可您们知道京东商品主图怎么保存到原图的吗?如果 ...
- 如何整店导出天猫店铺商品主图及详情图
怎样一键导出天猫的整店商品图片包含主图.详情图.属性图.及主图视频,今天小编选用一个好方法并能快速导出并分类保存,一起来看看. 1.双击打开载图助手,还没有安装的朋友可在百度上搜索并安装,如图: 2. ...
- 淘宝商品详情页API接口|tb获取商品主图接口
用到淘宝商品详情页API接口的用户,大部分是做电商软件,电商平台,商家等,使用到的比较常用的淘宝详情页API接口包括商品价格,商品主图,商品标题,SKU,店铺名称等等,还有以下几种: 淘宝商品详情页A ...
- 批量保存拼多多批发商城商品主图及视频
怎样可以一键采集出拼多多批发商城上多个商品主图及主图视频,并可以自动分类保存?其实现在在电商领域和一些影集图片的爱好收藏者,都在广泛使用一款叫载图助手的软件,其操作简单,支持平台广,均可批量采集,分类 ...
最新文章
- java清空栈_java - 如何使用Intent.FLAG_ACTIVITY_CLEAR_TOP清除活动堆栈?
- java中文乱码解决之道(二)—–字符编码详解:基础知识 + ASCII + GB**
- Linux打过cat没有编码,linux系统 终端下 cat中文乱码/vim不乱码 或者 cat不乱码/vim中文乱码...
- I2C 简介(备忘)
- 大学python笔记_Introduction to Python课程笔记
- python中解决中文乱码
- 边缘和智能,是谁在借谁上位?
- tp5 iis7 404 解决方案
- java中比较两个日期的大小
- 用计算机求锐角A,B,计算机操作题
- java如何引入qq登陆,Java Swing仿QQ登录界面 学习之用
- 术语html的含义是,术语html指的是什么
- 采集新浪微博数据建设网络舆情监测系统
- 关于VLAN的几种接口模式
- 【Java教程】Java 抽象工厂模式
- 华为服务器通过ilo虚拟光驱,如何通过ilo开启服务器远程桌面
- 冰点还原精灵图标不见了怎么办?
- python lncrna_使用CPAT分析lncRNA
- VUE中fetch结合支付宝API验证银行卡号
- echarts 双Y轴,双X轴, 折线图折点,折点与直方对应
热门文章
- Perfectly Clear WorkBench v4.0.0.2182 图像后期处理调色工具
- 数字货币区块链服务器交易平台面临着哪些安全威胁?
- 华为一日游 - 坂田基地家庭日见闻
- C# 或C++ 控制系统光驱弹出或关闭
- iOS 14:如何在iPhone和iPad上增强语音备忘录录音
- android-adb 打开手机端口进行无线模式调试
- 国内外著名IT公司技术岗位要求
- react初探-e.target为null
- 魔域私服怎么老服务器中断,教你如何在服务器重启后快速杀BOSS
- 校招行测笔试-数量关系