写点什么

基于 Vue 的商品主图放大镜方案

  • 2021-01-26
  • 本文字数:3771 字

    阅读完需:约 12 分钟

基于 Vue 的商品主图放大镜方案

前言


在做电商类应用时,难免会遇到商品主图实现放大镜效果的场景,现有的基于Vue的第三方包不多并且无法直接复用,今天,我来分享一种高稳定性的基于 Vue 的图片放大镜方法。

实现原理


放大镜的原理用一句话概括,就是根据小图上的鼠标位置去定位大图。



相信原理图已经画的很明白了, 图中,左侧框是小图框,其蓝色区域为图片遮罩层(需放大区域),右侧框是整个大图目前所在区域,其蓝色区域是放大区域,设置超出隐藏,就实现了放大遮罩区域的效果。


显然,两块蓝色区域存在着某种对应关系,即遮罩的左上角位置(相对于小图,以下称 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';}
复制代码


效果演示






核心代码

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,//放大比例    };  }}
复制代码


总结


其实图片放大镜的实现思路没有那么复杂,核心点有两点:


  • 小图、大图的定位,遮罩和放大区域的创建方法

  • 放大镜的原理理解,并用代码实现 dom 的移动等。


本文顺着这个思路,做了一个简单的实现,还有一些优化的空间,欢迎各位大佬在评论区讨论。虽然代码看起来不是非常优雅,但是足够明了,感兴趣的同学可以自己尝试一下。



头图:Unsplash

作者:一玲

原文:https://mp.weixin.qq.com/s/_4TEiywnmre1wdqHxQaPLg

原文:基于 Vue 的商品主图放大镜方案

来源:政采云前端团队 - 微信公众号 [ID:Zoo-Team]

转载:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


2021-01-26 23:472611
用户头像

发布了 78 篇内容, 共 34.8 次阅读, 收获喜欢 331 次。

关注

评论

发布
暂无评论
发现更多内容

码住!DolphinScheduler 常见故障 “急救指南”,一文解决服务、调度、连接等难题

白鲸开源

大数据 开源 技术 Apache DolphinScheduler 故障排查

Flink Agents:基于Apache Flink的事件驱动AI智能体框架

Apache Flink

大数据 flink 实时计算

Claude Code 从入门到精通:最全配置指南和工具推荐

Immerse

为什么舆情监测离不开海外社交媒体分析?

沃观Wovision

社交媒体 沃观Wovision 舆情监测系统 海外舆情监测

必看!Apache DolphinScheduler 任务组因 MySQL 时区报错全解析与避坑指南

白鲸开源

MySQL 大数据 开源 Apache DolphinScheduler 任务调度

(二)一文读懂数仓设计的核心规范:从层次、类型到生命周期

白鲸开源

数据库 大数据 数据仓库 命名规范

淘宝闪购实时分析黑科技:StarRocks + Paimon撑起秋天第一波奶茶自由

阿里云大数据AI技术

阿里云 饿了么 StarRocks 物化视图 湖仓

数据集成平台怎么选?从ETL到CDC再到iPaaS的全景对比

谷云科技RestCloud

数字化转型 ETL 集成平台 CDC ipaas

Openresty Tracing 最佳实践

观测云

openresty

谙流 ASK 技术解析(二):高性能低延迟

AscentStream

消息队列

MyEMS:开源能源管理的破局者

开源能源管理系统

开源 开源能源管理系统

揭秘LedgerCTF的AES白盒挑战:逆向工程与密码学分析

qife122

逆向工程 白盒密码学

Audition 入门教程:音频降速

北桥苏

Adobe Audition

避坑指南:1688商品详情API采集及常见错误码

tbapi

1688商品详情接口 1688API 1688商品数据采集 1688商品详情API 1688数据分析

看板方法的原则与实践

ShineScrum

Kanban 看板 看板工具

NJet支持使用json格式的配置文件了

通明湖

iPaaS 与传统 ESB 的区别,企业该如何选择?

谷云科技RestCloud

ESB API 数据传输 集成平台 ipaas

AI 在研发效能中的实际应用效果|《DevData 2025 研发效能基准报告》

思码逸研发效能

研发效能 研发效能度量 研发效能管理 智能编程 思码逸

再见 Cursor,Qoder 真香!这波要改写 AI 编程格局

阿里巴巴云原生

财务人必看:这款RPA让你少熬夜,多成长

Techinsight

告别资料混乱!PJMan 让项目文件管理,简单到不用找

Tecjt_锦图科技

项目管理

MyEMS:开源驱动下的企业能源管理革新者 —— 从技术架构到 “双碳” 落地的实践之路

开源能源管理系统

开源 开源能源管理系统

腾讯测试实践与工具分享之后台测试

优测云服务平台

测试工具

限时赠书|Altair 助力高校数据科学教育:中山大学教授发布RapidMiner 权威教材

Altair RapidMiner

人工智能 AI 数据分析 制造业 RapidMiner

SonicWall防火墙安全态势深度分析:固件解密与漏洞洞察

qife122

漏洞分析 SonicWall

舆情监测进入全球化时代,海外社交媒体分析是核心驱动力

沃观Wovision

社交媒体 沃观Wovision 舆情监测系统 海外舆情监测

扫描全能王“翻页自动拍”功能上线,AI扫描提升教师教学材料电子化效率

合合技术团队

“团队敏捷教练进阶课程”10月18-19日 · 在线A-CSM认证周末班

ShineScrum

Scrum 敏捷

私域商城物流模块开发实战:基于快递鸟API构建高效履约体系

快递鸟

1688商品列表API数据解析

tbapi

1688商品列表接口 1688API 1688数据采集 1688数据分析

Jira 官宣停售 Data Center ,中国企业又双叒要迁移了?!

万事ONES

Jira Atlassian 国产化替代 ONES研发管理

基于 Vue 的商品主图放大镜方案_编程语言_政采云前端团队_InfoQ精选文章