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 相关文章推荐
Javascript 继承实现例子
Aug 12 Javascript
js DataSet数据源处理代码
Mar 29 Javascript
jQuery实现点击标题输入详细信息
Apr 16 Javascript
jQuery实现的在线答题功能
Apr 12 Javascript
Node.js中Request模块处理HTTP协议请求的基本使用教程
Mar 31 Javascript
Three.js学习之正交投影照相机
Aug 01 Javascript
js 获取本地文件及目录的方法(推荐)
Nov 10 Javascript
webpack学习笔记之代码分割和按需加载的实例详解
Jul 20 Javascript
jQuery EasyUI window窗口使用实例代码
Dec 25 jQuery
JavaScript基础心法 数据类型
Mar 05 Javascript
JavaScript indexOf()原理及使用方法详解
Jul 09 Javascript
axios封装与传参示例详解
Oct 18 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 miniBB中文乱码问题解决方法
2008/11/25 PHP
PHP学习之数组的定义和填充
2011/04/17 PHP
win7安装php框架Yii的方法
2016/01/25 PHP
php文件上传 你真的掌握了吗
2016/11/28 PHP
关于firefox的ElementTraversal 接口 使用说明
2010/11/11 Javascript
javascript 折半查找字符在数组中的位置(有序列表)
2010/12/09 Javascript
nodejs简单实现中英文翻译
2015/05/04 NodeJs
javascript去除空格方法小结
2015/05/21 Javascript
Javascript实现字数统计
2015/07/03 Javascript
node-http-proxy修改响应结果实例代码
2016/06/06 Javascript
Javascript表单特效之十大常用原理性样例代码大总结
2016/07/12 Javascript
jQuery通过ajax方法获取json数据不执行success的原因及解决方法
2016/10/15 Javascript
简单实现jquery焦点图
2016/12/12 Javascript
解决ionic和angular上拉加载的问题
2017/08/03 Javascript
jQuery事件对象的属性和方法详解
2017/09/09 jQuery
详解VUE单页应用骨架屏方案
2019/01/17 Javascript
vue轮播组件实现$children和$parent 附带好用的gif录制工具
2019/09/26 Javascript
vue 微信扫码登录(自定义样式)
2020/01/06 Javascript
jQuery三组基本动画与自定义动画操作实例总结
2020/05/09 jQuery
vue绑定class的三种方法
2020/12/24 Vue.js
[04:22]DOTA2上海特级锦标赛主赛事第四日TOP10
2016/03/06 DOTA
Python 通过pip安装Django详细介绍
2017/04/28 Python
python遍历小写英文字母的方法
2019/01/02 Python
Python如何实现转换URL详解
2019/07/02 Python
Python Pandas实现数据分组求平均值并填充nan的示例
2019/07/04 Python
python如何实现异步调用函数执行
2019/07/08 Python
Python3中小括号()、中括号[]、花括号{}的区别详解
2020/11/15 Python
Opencv+Python识别PCB板图片的步骤
2021/01/07 Python
让IE支持HTML5的方法
2012/12/11 HTML / CSS
Algenist奥杰尼官网:微藻抗衰老护肤品牌
2017/07/15 全球购物
高分子材料个人求职信范文
2013/09/25 职场文书
银行柜员应聘推荐信范文
2013/11/24 职场文书
好的旅游活动方案
2014/08/19 职场文书
大学生入党群众意见书
2015/06/02 职场文书
科级干部培训心得体会
2016/01/06 职场文书
2019年幼儿园家长接送责任书
2019/10/29 职场文书