德胜云资讯,添加一些关于程序相关的内容,仅供大家学习交流(https://www.wxclwl.com)

网站地图

搜索
德胜云咨询
前端分类 javascript CSS 正则表达式 html 前端框架 typescript Ajax
热门标签:
最新标签:

html放大镜图标基于 Vue 的商品主图放大镜方案html放大代码原创,

日期:2023/03/23 20:48作者:王依婷人气:

导读:扫码关注公众号「政采云前端团队」,获取更多不掺水的原创好文~前言在做电商类应用时,难免会遇到商品主图实现放大镜效果的场景,现有的基于 Vue 的...

扫码关注公众号「政采云前端团队」,获取更多不掺水的原创好文~

前言

在做电商类应用时,难免会遇到商品主图实现放大镜效果的场景,现有的基于 Vue 的第三方包不多并且无法直接复用,今天,我来分享一种高鲁棒性的基于 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> <!-- 大图 --> <div class="magnifier-layer" :style="{ width:configs.width + px, height:this.configs.height+px, top:0px, left: configs.width + 20 + px }"> <div class="big-box" :style="{width:configs.scale * configs.width + px, height:configs.scale * configs.height + px}" > <div class="big-box-img" :style="{width:configs.scale * configs.width - 2 + px, height:configs.scale * configs.height - 2 + px}" > <img :src="bigSrc" :style="{maxWidth:configs.scale * configs.width - 2 + px, maxHeight:configs.scale * configs.height -2 + px}" /> </div> </div> </div> </div> </template>

js

这里主要有三个事件函数,handOver 鼠标进入到小图框上的事件,此时创建遮罩和放大区域,并计算小图框的位置信息。

handOver() { this.imgObj = this.$el.getElementsByClassName(small-box)[0]; // 创建遮罩区域 this.mouseMask = document.createElement(div); this.mouseMask.className = magnifier-zoom; this.mouseMask.style.background = this.configs.maskColor; this.mouseMask.style.height = this.configs.maskWidth + px; this.mouseMask.style.width = this.configs.maskHeight + px; this.mouseMask.style.opacity = this.configs.maskOpacity; // 创建预览框样式 this.imgLayer = document.getElementsByClassName(magnifier-layer)[0]; this.imgLayer.style.display = block; this.bigBox = document.getElementsByClassName(big-box)[0]; this.imgObj.appendChild(this.mouseMask); // 计算小图框在浏览器中的位置 this.imgRectNow = this.imgObj.getBoundingClientRect(); }

handMove 鼠标在小图上的移动事件,此事件发生在 handOver 之后,计算数据,移动遮罩以及背景图;

handMove(e) { // 计算初始的遮罩左上角的坐标 let objX = e.clientX - this.imgRectNow.left; let objY = e.clientY - this.imgRectNow.top; // 计算初始的遮罩左上角的坐标 let _maskX = objX - this.mouseMask.offsetHeight/2; let _maskY = objY - this.mouseMask.offsetWidth/2; // 判断是否超出界限,并纠正 _maskY = _maskY < 0 ? 0: _maskY; if(_maskY + this.mouseMask.offsetHeight >= imgRectNow.height){ _maskY = imgRectNow.height - this.mouseMask.offsetHeight; } _maskX = _maskX < 0 ? 0: _maskX; if(_maskX + this.mouseMask.offsetWidth >= imgRectNow.width){ _maskX = imgRectNow.width - this.mouseMask.offsetWidth; } let bigImgLeft = _maskX * this.configs.scale; let bigImgTop = _maskY * this.configs.scale; // 遮罩移动 this.mouseMask.style.transform=`translate(${_maskX}px, ${_maskY}px)`; // 背景图移动 this.bigBox.style.left = - bigImgLeft + "px"; this.bigBox.style.top = - bigImgTop + "px"; }

handOut 鼠标离开小图事件,此时无放大镜效果,隐藏遮罩和放大区域。

handOut() { this.imgLayer.style.display = none; this.mouseMask.style.display = none; }

以上三个事件基本上就实现了图片的放大镜功能。

但仔细看,你会发现每次移入小图框都会触发一次 handOver 事件,进而创建一份遮罩和放大区域等信息,其实,这些信息只需在页面加载后创建一次,多则浪费。

为了优化此问题,可以用 init 标识是否是页面加载后首次触发 handOver 事件,如果是初始化就创建遮罩和放大区域等,否则只需修改遮罩和放大区域的样式,使其显示即可。

handOver() { if (!this.init) { this.init = true; // 原 handOver 事件 ... } else { this.imgLayer.style.display = block; this.mouseMask.style.display = block; } },

在测试的过程中,发现页面滚动后,会出现遮罩定位错误的情况,原来是因为初始化时,我们定死了小图框的位置信息(存放在 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:{}, mouseMask:{}, imgLayer:{}, init: false, }; }, 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.mouseMask.offsetHeight/2; let _maskY = objY - this.mouseMask.offsetWidth/2; // 判断是否超出界限,并纠正 _maskY = _maskY < 0 ? 0: _maskY; if(_maskY + this.mouseMask.offsetHeight >= imgRectNow.height){ _maskY = imgRectNow.height - this.mouseMask.offsetHeight; } _maskX = _maskX < 0 ? 0: _maskX; if(_maskX + this.mouseMask.offsetWidth >= imgRectNow.width){ _maskX = imgRectNow.width - this.mouseMask.offsetWidth; } let bigImgLeft = _maskX * this.configs.scale; let bigImgTop = _maskY * this.configs.scale; // 遮罩移动 this.mouseMask.style.transform=`translate(${_maskX}px, ${_maskY}px)`; // 背景图移动 this.bigBox.style.left = - bigImgLeft + "px"; this.bigBox.style.top = - bigImgTop + "px"; }, handOut() { this.imgLayer.style.display = none; this.mouseMask.style.display = none; }, handOver() { if (!this.init) { this.init = true; this.imgObj = this.$el.getElementsByClassName(small-box)[0]; // 创建遮罩区域 this.mouseMask = document.createElement(div); this.mouseMask.className = magnifier-zoom; this.mouseMask.style.background = this.configs.maskColor; this.mouseMask.style.height = this.configs.maskWidth + px; this.mouseMask.style.width = this.configs.maskHeight + px; this.mouseMask.style.opacity = this.configs.maskOpacity; // 创建预览框样式 this.imgLayer = document.getElementsByClassName(magnifier-layer)[0]; this.imgLayer.style.display = block; this.bigBox = document.getElementsByClassName(big-box)[0]; this.imgObj.appendChild(this.mouseMask); } else { this.imgLayer.style.display = block; this.mouseMask.style.display = block; } } }

css

@prefixCls: ~magnifier; .@{prefixCls} { position: relative; font-size: 0; .small-box { width: 420px; height: 420px; cursor: move; text-align: center; display: table-cell; vertical-align: middle; border: 1px solid #E6E6E6; .smallPic { max-width: 418px; max-height: 418px; } } .magnifier-layer{ position: absolute; z-index: 9010; background: #fff; display: none; overflow: hidden; border: 1px solid #E6E6E6; box-shadow: 0 6px 20px 0 rgba(0,0,0,.1); .big-box { position: absolute; display: table-cell; vertical-align: middle; text-align: center; &-img { display: table-cell; vertical-align: middle; text-align: center; } } } .magnifier-zoom{ position: absolute; top:0; left:0; z-index: 20; pointer-events:none; } }

使用方法

本示例中的固定参数:小图框: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。

招贤纳士

政采云前端团队(ZooTeam),一个年轻富有激情和创造力的前端团队,隶属于政采云产品研发部,Base 在风景如画的杭州。团队现有 50 余个前端小伙伴,平均年龄 27 岁,近 3 成是全栈工程师,妥妥的青年风暴团。成员构成既有来自于阿里、网易的“老”兵,也有浙大、中科大、杭电等校的应届新人。团队在日常的业务对接之外,还在物料体系、工程平台、搭建平台、性能体验、云端应用、数据分析及可视化等方向进行技术探索和实战,推动并落地了一系列的内部技术产品,持续探索前端技术体系的新边界。

如果你想改变一直被事折腾,希望开始能折腾事;如果你想改变一直被告诫需要多些想法,却无从破局;如果你想改变你有能力去做成那个结果,却不需要你;如果你想改变你想做成的事需要一个团队去支撑,但没你带人的位置;如果你想改变既定的节奏,将会是“5 年工作时间 3 年工作经验”;如果你想改变本来悟性不错,但总是有那一层窗户纸的模糊… 如果你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的自己。如果你希望参与到随着业务腾飞的过程,亲手推动一个有着深入的业务理解、完善的技术体系、技术创造价值、影响力外溢的前端团队的成长历程,我觉得我们该聊聊。任何时间,等着你写点什么,发给 ZooTeam@cai-inc.com

排行

网站地图

Copyright © 2002-2022 香港德胜云网络 版权所有 | 备案号:蜀ICP备2023007363号-5

声明: 本站内容全部来自互联网,非盈利性网站仅供学习交流