js图片放大镜效果实现方法详解


Posted in Javascript onOctober 28, 2020

由项目需要,原生写了个详情页图片放大镜的效果,扔上代码供学习分享,也作为日常笔记...

效果如图(例子中偷偷链了张天猫的图片,希望没啥事 -。-):

js图片放大镜效果实现方法详解

实现过程教简单,但我们还是从css开始分析,过程如下(图片已正方形为例):

css:

/* 图片容器 */
 .imgBox{
 width: 200px; /* 各位大老爷们看着办 */
 height: 200px; /* 各位大老爷们看着办 */
 position: relative; /* 必需 */
 }

 /* 图片标签 */
 .mainImg{
 width: 100%; /* 各位大老爷们看着办,尽量100%好看些[斜眼笑] */
 height: 100%; /* 各位大老爷们看着办,尽量100%好看些[斜眼笑] */
 }

 /* 遮罩层-既放大区域 */
 .glass{
 position: absolute; /* 必需 */
 width: 50px; /* 遮罩层宽度 此处是放大4倍,所以为200/4=50 */
 height: 50px; /* 遮罩层高度 此处是放大4倍,所以为200/4=50 */
 top: -9999px; /* 绝对位置,先放远些 */
 left: -9999px; /* 绝对位置,先放远些 */
 cursor: move; /* 鼠标样式,好看些 */
 background: rgba(0,0,180,0.5); /* 遮罩层样式,好看些 */
 }

 /* 大图所在的容器 */
 .imgMax{
 position: absolute; /* 必需 */
 overflow: hidden; /* 必需,盖掉超出的大图[斜眼笑] */
 left: 210px; /* 必需,此处为距原图左边10像素 */
 top: 0; /* 必需,此处为距上边0像素 */
 width: 200px; /* 放大图片容器的宽度 此处此处是放大4倍,为200,保持和原图容器一般大,若此处为400,则是放大2*4倍,那么相应的放大图片应该是200*4*2=1600 */
 height: 200px; /* 放大图片容器的高度 此处此处是放大4倍,为200,保持和原图容器一般大,若此处为400,则是放大2*4倍,那么相应的放大图片应该是200*4*2=1600 */
 display: none; /* 先隐藏 */
 }
 .maxImg{
 position: absolute; /* 必需 */
 width: 800px; /* 此处是放大4倍,所以为200*4=800 受放大图片所在的容器影响,规则如上 */
 height: 800px; /* 此处是放大4倍,所以为200*4=800 受放大图片所在的容器影响,规则如上 */
 }

上面css中需要注意的就是几个position和缩放比例,注意调整下即可

写完样式,来看看布局:

html:

<!-- 图片容器 -->
 <div class="J_imgBox imgBox">
 <!-- 需要放大的图片-原始图 -->
 <img class="J_mainImg mainImg" src="http://img.alicdn.com/bao/uploaded/i7/TB1Xpe_NXXXXXXRXFXXGTq09XXX_035318.jpg_430x430q90.jpg" />
 <!-- 遮罩-既放大的区域 -->
 <div class="J_glass glass"></div>
 <!-- 大图的容器 -->
 <div class="J_imgMax imgMax">
 <!-- 大图 -->
 <img class="J_maxImg maxImg" />
 </div>
 </div>

接下来是主要的js代码,一如既往的带注解:

js:

(function(){
 /* 放大镜函数
 ** @imgContainer 需要实现放大镜效果的图片容器 此处是 class 为 J_imgBox 的 div
 */
 function imgZoom(imgContainer){

 // 取大图url,不知道淘宝图片规则如何,反正看了详情页的大图和小图url对比,随便写了个替换
 var imgUrl = imgContainer.querySelector('.J_mainImg').src.replace(/\.(jpg|jpeg|png|gif)(_)(\d+)(x)(\d+)(q90)?/g,'');

 // 取大图标签的节点
 var maxImg = imgContainer.querySelector('.J_maxImg');

 // 给该节点的src属性赋值为大图的url
 maxImg.src = imgUrl;

 // 取大图所在的容器
 var maxImgContainer = imgContainer.querySelector('.J_imgMax');

 // 取遮罩块
 var glassBlock = imgContainer.querySelector('.J_glass');

 // 取消放大镜效果
 var hideMaxImg = function(){
 glassBlock.style.top = '-9999px';
 glassBlock.style.left = '-9999px';
 maxImgContainer.style.display = 'none';
 }

 // 鼠标移出图片区域,取消放大镜效果
 imgContainer.onmouseout = function(event){
 event.stopPropagation();
 hideMaxImg();
 };

 // 鼠标在图片区域内移动事件
 imgContainer.onmousemove = function(event) {
 event.stopPropagation();

 // 取图片容器的大小及其相对于视口的位置,需要实时取,所以放在move事件里
 var clientRect = event.currentTarget.getBoundingClientRect();

 // 获取距鼠标距的上和左的坐标
 var leftX = event.clientX - clientRect.left;
 var leftY = event.clientY - clientRect.top;

 // 动态设置遮罩块的left和top位置 这里需要减去遮罩层的一半,因为鼠标位于遮罩块中心点
 var pointerLeft = leftX - 25;
 var pointerTop = leftY - 25;

 // 如果鼠标坐标移动超出原始图片区域边缘 则取消放大镜效果 因为这里存在快速移动鼠标到大图区域时,鼠标仍处在外层的图片区域内,并不会触发mouseout事件(虽然中间隔了小小的间距,但是快速移动仍能产生这个bug,如代码下面的图所示)
 if((pointerLeft+25) > clientRect.width || pointerLeft < 0 - 25 || (pointerTop+25) > clientRect.height || pointerTop < 0 - 25){
 hideMaxImg();
 return !1;
 };

 // 遮罩块在最左边的时候,鼠标仍在图片区域内,可在遮罩块左边缘至中心线区域内移动,且这时遮罩块为距左0像素
 if(pointerLeft < 0){
 pointerLeft = 0;
 };

 // 同上 右边限制
 if(pointerLeft > clientRect.width - 50){
 pointerLeft = clientRect.width - 50;
 };

 // 同上 顶部限制
 if(pointerTop < 0){
 pointerTop = 0;
 };

 // 同上 底部限制
 if(pointerTop > clientRect.height - 50){
 pointerTop = clientRect.height - 50;
 };

 // 设置遮罩块的位置
 glassBlock.style.left = pointerLeft;
 glassBlock.style.top = pointerTop;

 // 取遮罩快距离左边的位置和图片区域的宽高比,用于计算大图偏移距离,展示遮罩块所对应的图片区域
 var percentLeft = pointerLeft/clientRect.width;
 var percentHeight = pointerTop/clientRect.height;

 // 设置大图偏移距离 因为其父元素存在 overflow:hidden 所以只会展示对应区块
 maxImg.style.left = -(percentLeft*maxImg.clientWidth)+'px';
 maxImg.style.top = -(percentHeight*maxImg.clientHeight)+'px';
 };
 }

 var elem = document.querySelectorAll('.J_imgBox');

 elem.forEach(function(item,idx){
 imgZoom(item)
 })
 })()

补bug图:

js图片放大镜效果实现方法详解

看完后是不是觉得简直不要太简单,接下来就来理一理以上代码中能够抽取出来在平常开发中比较实用的知识点:

Element.getBoundingClientRect()

Element.getBoundingClientRect()方法返回元素的大小及其相对于视口的位置

例子:

<body style="width:1400;height:1000">
<div id="testDiv" style="width:10px;height:20px;background:#f00"></div>
<script>
(function(){
var elem = document.getElementById('testDiv');
document.body.addEventListener('click',function(){
console.log(elem.getBoundingClientRect())
},false)
})()
</script>
</body>

效果如图:

js图片放大镜效果实现方法详解

从效果图上不难看出,当我移动视图后再点击body,打印的对象都能够正确返回元素的大小及其相对于视口的位置

这个方法也可以用于实现当某元素滚动到底/顶部时触发对应事件,相当方便。

Event

1.event.target 和 event.currentTarget

    target:指向触发事件的元素

    currentTarget:指向被绑定事件句柄的元素

    只有当绑定的事件处理程序与触发该事件处理程序都为同一个对象的时候,两者相同

    例子代码:

    html:

<div id="aDiv">
 123
 <div id="bDiv">456</div>
 </div>

js:

document.getElementById('aDiv').addEventListener('click',function(e){
 if(e.target === e.currentTarget) {
 console.log('target === currentTarget')
 }else{
 console.log('target !== currentTarget')
 }
 console.log('target',e.target)
 console.log('currentTarget',e.currentTarget)
 },false)

    效果图:

js图片放大镜效果实现方法详解

    从效果图中,我们可以看到,当点击456时,target指向的是456所在的bDiv,currentTarget则指向aDiv,因为事件是绑定在aDiv上,但触发是在bDiv上,而且bDiv又在aDiv内,当点击123时,则target与currentTarget一致,绑定和触发都在aDiv上。

2.event.preventDefault() & event.stopPropagation()

    preventDefault:如果事件可取消,则取消该事件,而不停止事件的进一步传播

    stopPropagation:阻止捕获和冒泡阶段中当前事件的进一步传播

3.event.stopPropagation() & event.stopImmediatePropagation()

    stopPropagation:阻止捕获和冒泡阶段中当前事件的进一步传播

    stopImmediatePropagation:阻止元素上调用相同事件的其他事件监听并阻止冒泡

    两者区别的例子:

  html:

<div id="aDiv">
 123
 <div id="bDiv">456</div>
 </div>

    js:

document.getElementById('aDiv').addEventListener('click',function(){
 console.log('click aDiv')
 },false)
 document.getElementById('bDiv').addEventListener('click',function(e){
 e.stopImmediatePropagation();
 console.log('click bDiv')
 },false)
 document.getElementById('bDiv').addEventListener('click',function(){
 console.log('click me too')
 },false)

上面代码执行结果为:

click bDiv

注释掉 e.stopImmediatePropagation(); 的结果为:

click bDiv
click me too
click aDIV
 

虽然都是些简单的知识点,在平常开发中也是很实用的,希望能从细节出发,没事多复习复习 -。-~

后来一时兴起将放大镜写的更傻瓜式配置的插件了... 点我看代码(github地址)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
UI Events 用户界面事件
Jun 27 Javascript
JS动态添加与删除select中的Option对象(示例代码)
Dec 25 Javascript
js获取当前页面的url网址信息
Jun 12 Javascript
详解Javascript模板引擎mustache.js
Jan 20 Javascript
仅30行代码实现Javascript中的MVC
Feb 15 Javascript
基于jQuery Ajax实现上传文件
Mar 24 Javascript
JavaScript评论点赞功能的实现方法
Mar 13 Javascript
Google 爬虫如何抓取 JavaScript 的内容
Apr 07 Javascript
详解react如何在组件中获取路由参数
Jun 15 Javascript
vue.js内置组件之keep-alive组件使用
Jul 10 Javascript
H5实现手机拍照和选择上传功能
Dec 18 Javascript
微信小程序实现下滑到底部自动翻页功能
Mar 07 Javascript
js a标签点击事件
Mar 30 #Javascript
JS+html5制作简单音乐播放器
Sep 13 #Javascript
TypeScript入门-接口
Mar 30 #Javascript
如何编写jquery插件
Mar 29 #jQuery
基于JavaScript实现瀑布流效果
Mar 29 #Javascript
Angular动态添加、删除输入框并计算值实例代码
Mar 29 #Javascript
JS变量及其作用域
Mar 29 #Javascript
You might like
最新的php 文件上传模型,支持多文件上传
2009/08/13 PHP
PHP连接SQLServer2005的实现方法(附ntwdblib.dll下载)
2012/07/02 PHP
php中将html中的br换行符转换为文本输入中的换行符
2013/03/26 PHP
PHP中的排序函数sort、asort、rsort、krsort、ksort区别分析
2014/08/18 PHP
朋友网关于QQ相关的PHP代码(研究QQ的绝佳资料)
2015/01/26 PHP
php实现比较全的数据库操作类
2015/06/18 PHP
yum命令安装php7和相关扩展
2016/07/04 PHP
php中get_magic_quotes_gpc()函数说明
2017/02/06 PHP
javascript SocialHistory 检查访问者是否访问过某站点
2008/08/02 Javascript
jQuery 连续列表实现代码
2009/12/21 Javascript
动态加载外部javascript文件的函数代码分享
2011/07/28 Javascript
JavaScript限定图片显示大小的方法
2015/03/11 Javascript
基于jquery实现放大镜效果
2015/08/17 Javascript
jQuery自定义元素右键点击事件(实现案例)
2017/04/28 jQuery
JavaScript比较两个数组的内容是否相同(推荐)
2017/05/02 Javascript
对vuejs的v-for遍历、v-bind动态改变值、v-if进行判断的实例讲解
2018/08/27 Javascript
解决js相同的正则多次调用test()返回的值却不同的问题
2018/10/10 Javascript
微信小程序开发的基本流程步骤
2019/01/31 Javascript
详解javascript void(0)
2020/07/13 Javascript
[05:46]DOTA2英雄梦之声_第18期_陈
2014/06/20 DOTA
Python使用三种方法实现PCA算法
2017/12/12 Python
详解Python3中的迭代器和生成器及其区别
2018/10/09 Python
简单了解python单例模式的几种写法
2019/07/01 Python
TensorFlow车牌识别完整版代码(含车牌数据集)
2019/08/05 Python
Python爬虫使用bs4方法实现数据解析
2020/08/25 Python
Pyqt助手安装PyQt5帮助文档过程图解
2020/11/20 Python
浅析pandas随机排列与随机抽样
2021/01/22 Python
python re模块常见用法例举
2021/03/01 Python
同学聚会策划方案
2014/06/06 职场文书
助残日活动总结
2014/08/27 职场文书
房产协议书范本
2014/10/18 职场文书
2014年质检工作总结
2014/11/26 职场文书
小学五年级语文上册教学计划
2015/01/22 职场文书
工艺技术员岗位职责
2015/02/04 职场文书
MySQL 服务和数据库管理
2021/11/11 MySQL
python数字类型和占位符详情
2022/03/13 Python