闲来无聊, 看到百度图片 hover 的时候提示框的效果, 遂想试一试自己能否实现.
百度图片 hover 的效果:
需求:
1. 当鼠标从图片上部移入的时候, 提示框从上部移到正常位置. 从上部移出的时候, 提示框从正常位置移到上部.
2. 当鼠标从图片左部移入的时候, 提示框从左部移到正常位置. 从左部移出的时候, 提示框从正常位置移到左部
3. 当鼠标从图片右部移入的时候, 提示框从右部移到正常位置. 从右部移出的时候, 提示框从正常位置移到右部
4. 当鼠标从图片下部移入的时候, 提示框从下部移到正常位置. 从下部移出的时候, 提示框从正常位置移到下部
先上实现的效果图:
实现原理:
1. 把图片看做一个矩形, 把这个矩形, 按对角线分成四份, 每一份对应上下左右的部分.
2. 获取鼠标移入 div 之后的坐标, 获取该 div 离浏览器顶部和左部的距离, 就能知道在该 div 中, 鼠标移入的坐标.
3. 以 div 左上角为原点, 水平和竖直方向做坐标轴.
4. 算出移入的点与 x 轴的夹角 β 和 θ. 再与 α 角做比较, 最后判断是在哪个范围内的.
如图:
说明:
1) β,θ是移入的点与 x 轴的夹角, 求这两个角与 α 的关系, 才能知道到底是在哪个区域
2) 已知条件: x,y,x0,y0. 分别代表图片宽和高, 移入的 x,y 坐标.
3) 不管是鼠标从哪个区域移入或移出, 只要求到移入的点与 x 轴的夹角的大小关系, 就能正确判断.
夹角判断所在区域:
当 0 < β α, 移入的点在 1 和 4 区域,
当 α < β 90, 移入的点在 2 和 3 区域,
当 0 < θ α, 移入的点在 1 和 2 区域,
当 α < θ 90, 移入的点在 3 和 4 区域,
那么, 要判断在 1 区域里面的话, 满足的条件就必须为: 0 < β α,0 < θ α 以此类推...
原理搞清楚了, 就可以上代码了.
- 1. html
- <div class="box">
- <img src="upimg/comm.png"/>
- <div class="innerBox">
- <div class="inner"></div>
- </div>
- </div>
说明: box 是装图片的一个列表, innerBox 是装提示框的盒子, inner 是提示框的内容, inner 也要设置绝对定位是因为只有这样才能设置 top 和 left 值. 实际上就相当于给人错觉提示框 innerBox 在移动, 实际上是提示框里的内容 inner 在移动.
- 2. CSS
- *{
- padding:0;
- margin: 0;
- }
- .box{
- width: 300px;
- height: 300px;
- background: skyblue;
- float: left;
- position: relative;
- overflow: hidden;
- margin:10px 10px 0 0;
- }
- .innerBox{
- position: absolute;
- bottom: 0;
- left: 0;
- width: 100%;
- height: 40px;
- }
- img{
- width: 100%;
- }
- .inner{
- position: absolute;
- top:40px;
- left: 0;
- width: 100%;
- height: 40px;
- background: red;
- }
- 3. js
- $('.box').hover(function(e){
- getIn($(this),e)
- },function(e){
- getOut($(this),e)
- })
- // 获取在第几区域
- function getdirection(obj,e){
- var bleft=obj.offset().left;// 距离左部的大小
- var btop=obj.offset().top;// 距离顶部的大小
- var li_w=obj.width();// 每个图片的宽度
- var li_h=obj.height();// 每个图片的高度
- var evt=e||window.event;
- var x=evt.pageX-bleft;// 鼠标在该图片中的 x 坐标
- var y=evt.pageY-btop;// 鼠标在该图片中的 y 坐标
- x=Math.abs(x);// 这里是防止移出的时候, x 的值为负 (bleft 的值大于 pageX)
- y=Math.abs(y);// 与上同理
- if(x>li_w){
- x=li_w-(x-li_w);// 这里是防止在第四部分移出的时候, pageX 的值大于图片的长度, 所以需要用到长度减去多余的部分就是在第四区域的对称位置
- }
- var Alltan=Math.atan(li_h/li_w);// 这是α
- var leftTan=Math.atan(y/x);// 这是β
- var rightTan=Math.atan(y/(li_w-x));// 这是θ
- if(0<=leftTan&&leftTan<=Alltan&&0<=rightTan&&rightTan<=Alltan){
- console.log("在第一部分")
- return 1;
- }else if(Alltan<=leftTan&&leftTan<=Math.asin(1)&&0<=rightTan&&rightTan<=Alltan){
- console.log("在第二部分");
- return 2;
- }else if(Alltan<=leftTan&&leftTan<=Math.asin(1)&&Alltan<=rightTan&&rightTan<=Math.asin(1)){
- console.log("在第三部分");
- return 3;
- }else if(0<=leftTan&&leftTan<=Alltan&&Alltan<=rightTan&&rightTan<=Math.asin(1)){
- console.log("在第四部分");
- return 4;
- }
- }
- // 移入
- function getIn(obj,e){
- var statu=getdirection(obj,e);
- var li_w=obj.width();
- var that=obj.find('.inner');
- var child_h=that.height();
- if(statu===1){
- that.css({
- "left":0,
- "top":-child_h
- }).stop().animate({
- "top":0
- },200)
- }else if(statu===2){
- that.css({
- "left":-li_w,
- "top":0
- }).stop().animate({
- "left":0
- },200)
- }else if(statu===3){
- that.stop().animate({
- "top":0
- },200)
- }else if(statu===4){
- that.css({
- "left":li_w,
- "top":0
- }).stop().animate({
- "left":0
- },200)
- }
- }
- // 移出
- function getOut(obj,e){
- var statu=getdirection(obj,e);
- var li_w=obj.width();
- var that=obj.find('.inner');
- var child_h=that.height();
- if(statu===1){
- that.stop().animate({
- "top":-child_h
- },200,function(){
- $(this).css({
- "left":0,
- "top":child_h
- })
- })
- }else if(statu===2){
- that.stop().animate({
- "left":-li_w
- },200,function(){
- $(this).css({
- "left":0,
- "top":child_h
- })
- })
- }else if(statu===3){
- that.stop().animate({
- "top":child_h
- },200)
- }else if(statu===4){
- that.stop().animate({
- "left":li_w
- },200,function(){
- $(this).css({
- "left":0,
- "top":child_h
- })
- })
- }
- }
说明: Math.asin(1) 表示 90 度的反正弦值, 由于 tan90 不存在, 所以换成 sin90 了.
总结: 对比自己做的和百度的图片效果, 发现百度的动画给人明显的要舒服点, 估计是因为移出的时候, 我直接设置 css, 导致动画不连贯原因, 还有个就是 stop() 导致动画直接结束, 所以还有可以修改的地方. 这里只介绍一个思路
来源: https://www.cnblogs.com/zjjDaily/p/9138820.html