这里是简单的js放大镜功能的实现
主要使用了三种鼠标事件类型进行操作(
mouseenter
,mousemove
,mouseleave
)
实际原理是利用原始图片盒子中的放大镜进行位移,让放大的图片在右边的盒子进行相反方向的等比例位移,以此达到放大商品的效果
先写好html,代码如下:
html代码很简单,就是一个大的容器(section)中有两个小容器(leftBox,rightBox),左侧容器为原图,右侧为放大后的图片(感觉像是障眼法),html写好后准备写css样式
css样式如下:
.box {
height: 600px;
width: 1000px;
margin: 50px auto;
overflow: hidden;
}
.leftBox,
.rightBox {
height: 450px;
width: 450px;
float: left;
position: relative;
}
.rightBox {
height: 550px;
width: 550px;
display:none;
overflow: hidden;
}
.smallBox {
position: absolute;
height: 150px;
width: 150px;
background-color: rgba(255, 0, 0, 0.3);
top: 0;
left: 0;
cursor: move;
border-radius: 50%;
}
.rightBox>img {
position: absolute;
width: 1650px;
height: 1650px;
}
我们先把大的容器宽高固定好,防止高度塌陷.
这里我们的左边原始图片的容器和右边放大图片的容器需要自己提前设置好,我这里设置了左边容器宽高为450px,右边的容器稍大一点为550px.对两个盒子进行浮动让其显示在一行.
在这里事先设置好原始图片中的放大镜的样式,宽高设置为150px,相对父元素绝对定位
上面设置好放大镜的宽高为原始图片的1/3,所以放大的图片也需要设置为右边容器3倍
样式设置完毕后,下面开始js部分
js代码如下:
先附上完整的,后面再一一解析:
var leftBox, smallBox, rightBox, img;
init();
function init() {
leftBox = document.querySelector('.leftBox');
rightBox = document.querySelector('.rightBox');
img = rightBox.querySelector('img');
leftBox.addEventListener('mouseenter', mouseHandler);
}
function mouseHandler(e) {
if (e.type === 'mouseenter') {
rightBox.style.display = 'block';
smallBox = document.createElement('div');
smallBox.className = 'smallBox';
this.appendChild(smallBox);
this.addEventListener('mousemove', mouseHandler);
this.addEventListener('mouseleave', mouseHandler);
} else if (e.type === 'mousemove') {
var curL = e.pageX - e.currentTarget.offsetLeft - smallBox.offsetWidth / 2,
curT = e.pageY - e.currentTarget.offsetTop - smallBox.offsetHeight / 2;
var minL = 0,
minT = 0,
maxL = e.currentTarget.offsetWidth - smallBox.offsetWidth,
maxT = e.currentTarget.offsetHeight - smallBox.offsetHeight;
curL = curL < minL ? minL : (curL > maxL ? maxL : curL);
curT = curT < minT ? minT : (curT > maxT ? maxT : curT);
smallBox.style.left = curL + 'px';
smallBox.style.top = curT + 'px';
img.style.left = -curL * 4 + 'px';
img.style.top = -curT * 4 + 'px';
} else if (e.type === 'mouseleave') {
rightBox.style.visibility = 'none';
this.removeChild(smallBox);
smallBox = null;
this.removeEventListener('mousemove', mouseHandler);
this.removeEventListener('mouseleave', mouseHandler);
}
}
第一步,先初始化需要的操作的元素的变量,我们这里需要操作四个元素,分别为左边的原始图片盒子,右边的放大图片盒子,放大镜的盒子,以及要操作的放大图片
第二步,初始化函数(一开始需要对哪些元素进行操作),依次利用querySelector获取的需操作的元素的选择器名,再对左边原始图片盒子增加一个事件监听器,事件类型为鼠标事件中的
mouseenter
,事件处理程序的回调函数为mouseHandler
这里选择
mouseenter
和mouseover
是存在很大区别的:
+1.mouseenter
在进入父容器中的子元素时,不会触发冒泡传播机制(子元素也是在父容器中)
+2.mouseover
会触发冒泡传播机制,在进入到放大镜盒子后,鼠标此时离开了父容器进入了子元素
var leftBox, smallBox, rightBox, img;
init();
function init() {
leftBox = document.querySelector('.leftBox');
rightBox = document.querySelector('.rightBox');
img = rightBox.querySelector('img');
leftBox.addEventListener('mouseenter', mouseHandler);
}
初始化函数完成以后,进入事件回调函数的编写:
在这个函数中,主要由三部分组成
第一部分,当此时的事件类型为
mouseenter
时,执行第一条条件语句中的内容:
- 1.因为一开始的右侧盒子为隐藏状态,只有当鼠标移入左侧盒子时才会显现出来
- 2.一开始是并不存在放大镜的,只有当鼠标移入左侧盒子后才会生成放大镜,所以我们需要生成一个放大镜的'div',并将其增加我们一开始在css中所写的类名'smallBOx',最后再将创建好的放大镜盒子放入左侧盒子中
- 3.因为鼠标是在左侧盒子中移动的,所以当进入它后,再为其添加两个事件监听,分别为
mousemove
和mouseleave
,事件回调函数也为此函数(下次进入只需要判断事件类型即可)
if (e.type === 'mouseenter') {
rightBox.style.display = 'block';
smallBox = document.createElement('div');
smallBox.className = 'smallBox';
this.appendChild(smallBox);
this.addEventListener('mousemove', mouseHandler);
this.addEventListener('mouseleave', mouseHandler);
}
第二部分,当事件类型为'mousemove'时,进入第二条条件语句
-
1.首先我们需要知道,当鼠标移入左侧盒子时,需要让放大镜跟随鼠标(其实就是求出放大镜在鼠标移入这个位置的left和top值),所以我们先要知道此时的鼠标距离页面的左边和上边的距离,可以用到事件对象中的属性
pageX
和pageY
(意思为当前鼠标到body的左边和上边的距离,其实再没有滚动条的情况下,使用clientX和clientY也是可行的)得到,再减去leftBox的左偏移量和上偏移量,再减去samllBox的实际宽高的一半,最后求出smallBox的left和top在鼠标位置的实际值 -
2.但是smallBox的定位只能在leftBox里面,所以我们还要求出定位的最大值和最小值:
-
最小值就是为0;
-
最大值十leftBox的实际宽高减去smallBox的实际宽高
-
最后进行判断,当小于最小值时,让其去最小值,否则当它大于最大值时让其取最大值(这样就不会超出leftBox的宽高)
-
3.给smallBox设置定位
-
4.给大图设置相反方向的定位,比例其实就是:
-
缩放比例: smallBox实际宽高 : leftBox的实际宽高 = rightBox的实际宽高 : 放大的图片宽高
-
移动比例: smallBox的left(top) * (放大的图片宽高 : rightBox的实际宽高) = 放大的图片宽高 * (rightBox的实际宽高 : leftBox的实际宽高)
else if (e.type === 'mousemove') {
var curL = e.pageX - e.currentTarget.offsetLeft - smallBox.offsetWidth / 2,
curT = e.pageY - e.currentTarget.offsetTop - smallBox.offsetHeight / 2;
var minL = 0,
minT = 0,
maxL = e.currentTarget.offsetWidth - smallBox.offsetWidth,
maxT = e.currentTarget.offsetHeight - smallBox.offsetHeight;
curL = curL < minL ? minL : (curL > maxL ? maxL : curL);
curT = curT < minT ? minT : (curT > maxT ? maxT : curT);
smallBox.style.left = curL + 'px';
smallBox.style.top = curT + 'px';
img.style.left = -curL * 4 + 'px';
img.style.top = -curT * 4 + 'px';
}
第三部分是当鼠标离开leftBox时,再次将rightBox隐藏起来,并且移除原来生成的smallBox(因为每一次移入都会生成一个,所以为了性能,需要将上一个的smallBox移除),最后在移除leftBox的鼠标滑动
mousemove
和鼠标离开mouseleave
事件监听(与samllBox原理一样);
else if (e.type === 'mouseleave') {
rightBox.style.display = 'none';
this.removeChild(smallBox);
smallBox = null;
this.removeEventListener('mousemove', mouseHandler);
this.removeEventListener('mouseleave', mouseHandler);
}