jQuery实现拉勾穿墙效果
A 预备知识
A1 思路
HTML结构是每一个展示框都附带了一个随着鼠标滑过的遮罩层(mask)。每当鼠标在展示框上移入移出的时候,判断鼠标的方向,让遮罩层来跟随鼠标的移动。
由于遮罩层只有一个,每次鼠标移入时,让遮罩层瞬间定位,然后沿着鼠标的方向进入,最终的目标就是和展示框的位置完全重合。
离开时正好相反,起点是和展示框完全重合的位置,终点就是遮罩层刚刚离开展示框。
行为如下图所示:
A2 知识储备
- 一丢丢平面几何的知识
- js中盒子模型属性
- jQuery的animate动画
- 事件源的属性
B 代码堆积
B1 HTML结构
<ul id="list">
<li>
![](images/aiqiyi.jpg)
<div class="mask">爱奇艺</div>
</li>
...
</ul>
img是要穿过的图片
mask是遮罩层
li相对定位,mask绝对定位
B2 绑定事件
var $li = $('#list').children('li');
$li.each(function () {
fn($(this));
});
遍历所有的li,在函数fn里为其绑定移入和移出事件
function fn($box) {
var nWidth = $box.outerWidth();
var nHeight = $box.outerHeight();
var $mask = $box.children('.mask');
}
获得每个li的宽高,这个宽高也是遮罩层运动的距离。
获得遮罩层。
//在fn里,为每个li绑定移入事件
$box.mouseenter(function (e) {
var x = e.clientX - $(this).offset().left - this.offsetWidth / 2;
var y = $(this).offset().top + this.offsetHeight / 2 - e.clientY;
};
此入的x和y,是相对于各自的li的中心。
鼠标的实时位置,相对于li的中心点的坐标,可以根据上图这样来算出
y = li高度/2 - (鼠标实时距页面边距b - li相对页面的偏移a);
x = 鼠标实时距页面边距d - li相对页面的偏移c - li宽度/2;
备注:li距页面的边距不一定就是通过ele.offset.top来获得,如果中间嵌套了其他定位元素,可以由其他盒子模型属性来获得。
因为要根据这个xy值来判断,是哪个方向,而且离开的时候还是要根据这个来判断,所以将判断方法封装成一个方法,返回值有四种情况,来代码是从哪个方向进入和移出。
function getDirction(x, y) {
//获得方向的弧度制
var rad = Math.atan2(y, x);
//获得方向的角度制,具体角度分布见下图
var angle = 180 * rad / Math.PI;
//将角度经过一系列运算,最终得到四个方向四个值,返回出去
return Math.round((angle + 180) / 90) % 4;
}
由于得到的5个值,左边进入有两值,再进行%4
操作,就可以精简为四个值,分别0代表从左侧进入,1借债有从下侧进入,2代码从右侧进入,3代表从上侧进入。
在鼠标移入事件中得到方向,来控制mask的进入初始位置。
$box.mouseenter(function (e) {
var x = e.clientX - $(this).offset().left - this.offsetWidth / 2;
var y = $(this).offset().top + this.offsetHeight / 2 - e.clientY;
var val = getDirction(x, y);
switch (val) {
case 0:
$mask.css({'left': -nWidth, 'top': 0});
break;
case 1:
$mask.css({'top': nHeight, 'left': 0});
break;
case 2:
$mask.css({'top': 0, 'left': nWidth});
break;
case 3:
$mask.css({'top': -nHeight, 'left': 0});
}
//无论从哪个方向进入,最终的目标点都是一样的,即和li完全重合,就是起始的位置不同
$mask.stop().animate({'left': 0, 'top': 0});
});
同样由此可以得出,移出事件
$box.mouseleave(function (e) {
var x = e.clientX - $(this).offset().left - this.offsetWidth / 2;
var y = $(this).offset().top + this.offsetHeight / 2 - e.clientY;
var val = getDirction(x, y);
var target;
switch (val) {
case 0:
target = {'left': -nWidth, 'top': 0};
break;
case 1:
target = {'top': nHeight, 'left': 0};
break;
case 2:
target = {'top': 0, 'left': nWidth};
break;
case 3:
target = {'top': -nHeight, 'left': 0};
}
$mask.stop().animate(target);
});
移出事件正好和移入相反,移出的时候起始点是一样的,而离开的时候需要判断是从哪个方向出去。