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 相关文章推荐
jquery $.ajax入门应用二
Nov 19 Javascript
JS setCapture 区域外事件捕捉
Mar 18 Javascript
基于jquery的点击链接插入链接内容的代码
Jul 31 Javascript
JavaScript实现多维数组的方法
Nov 20 Javascript
JavaScript日期时间格式化函数分享
May 05 Javascript
AngularJs Understanding the Model Component
Sep 02 Javascript
使用AngularJS 跨站请求如何解决jsonp请求问题
Jan 16 Javascript
老生常谈js-react组件生命周期
May 02 Javascript
基于es6三点运算符的使用方法(实例讲解)
Oct 12 Javascript
ES6新增的数组知识实例小结
May 23 Javascript
IDEA配置jQuery, $符号不再显示黄色波浪线的问题
Oct 09 jQuery
Vue router传递参数并解决刷新页面参数丢失问题
Dec 02 Vue.js
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中的字符串函数
2006/11/24 PHP
基于empty函数的输出详解
2013/06/17 PHP
解析Ubuntu下crontab命令的用法
2013/06/24 PHP
PHP实现将textarea的值根据回车换行拆分至数组
2015/06/10 PHP
php实现在服务器端调整图片大小的方法
2015/06/16 PHP
php实现等比例压缩图片
2018/07/26 PHP
JS 自动安装exe程序
2008/11/30 Javascript
父子窗体间传递JSON格式的数据的代码
2010/12/25 Javascript
一个基于jQuery的树型插件(OrangeTree)使用介绍
2012/05/03 Javascript
javascript实现锁定网页、密码解锁效果(类似系统屏幕保护效果)
2014/08/15 Javascript
如何用JavaScript定义一个类
2014/09/12 Javascript
javascript框架设计读书笔记之模块加载系统
2014/12/02 Javascript
jQuery简单操作cookie的插件实例
2016/01/13 Javascript
jQuery选择器基础入门教程
2016/05/10 Javascript
jQuery实现图片轮播效果代码(基于jquery.pack.js插件)
2016/06/02 Javascript
深入理解vue.js双向绑定的实现原理
2016/12/05 Javascript
javascript 缓冲运动框架的实现
2017/09/29 Javascript
手机注册发送验证码倒计时的简单实例
2017/11/15 Javascript
微信网页授权并获取用户信息的方法
2018/07/30 Javascript
手把手教你使用TypeScript开发Node.js应用
2019/05/06 Javascript
js实现有趣的倒计时效果
2021/01/19 Javascript
Python random模块(获取随机数)常用方法和使用例子
2014/05/13 Python
python框架中flask知识点总结
2018/08/17 Python
对python自动生成接口测试的示例讲解
2018/11/30 Python
Python-接口开发入门解析
2019/08/01 Python
使用keras2.0 将Merge层改为函数式
2020/05/23 Python
numpy中生成随机数的几种常用函数(小结)
2020/08/18 Python
Html5实现iPhone开机界面示例代码
2013/06/30 HTML / CSS
Html5 webRTC简单实现视频调用的示例代码
2020/09/23 HTML / CSS
英语自荐信范文
2013/12/11 职场文书
毕业生自荐书
2013/12/18 职场文书
雨花台导游词
2015/02/06 职场文书
2016年寒假社会实践活动心得体会
2015/10/09 职场文书
Consul在linux环境的集群部署
2022/04/08 Servers
Nginx 配置 HTTPS的详细过程
2022/05/30 Servers
Spring Boot 的创建和运行示例代码详解
2022/07/23 Java/Android