javascript鼠标跟随运动3种效果(眼球效果,苹果菜单,方向跟随)


Posted in Javascript onOctober 27, 2016

运动除了直线运动和曲线运动两种运动形式外,还有一种运动形式是鼠标跟随运动,而这种跟随运动需要用到三角函数的相关内容或者需要进行比例运算。本文将以几个小实例来介绍角度运动的相关内容

眼球转动

在很多网页中,都存在着跟随运动,比如眼球转动。鼠标在网页中移动时,眼球也会跟着朝相应方向转动

javascript鼠标跟随运动3种效果(眼球效果,苹果菜单,方向跟随)

上面是眼球转动的示意图,(x0,y0)是眼球的位置,而(x,y)是鼠标的位置。设直线与垂直方向的夹角为a,假设圆心点坐标为(0,0),可以得到以下公式

tan(a) = x/y = x0/y0
x0 = r*sin(a) 
y0 = r*cos(a)

在mousemove事件中,可以很容易的得到鼠标位置(x,y),由此求出夹角a,进而可以求出眼球的位置

设左眼为ball1,右眼为ball2。左眼的圆心坐标是(39,72),右眼的圆心坐标是(106,68),眼球可以移动的半径是12px

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
#test{position: absolute;top: 100px;left: 200px;}
#ball1{position: absolute;top: 62px;left: 28px;}
#ball2{position: absolute;top: 58px;left: 96px;}
</style>
</head>
<body>
<div id="test">
  <img src="head.png" alt="body">  
  <img id="ball1" src="ball.png" alt="ball">
  <img id="ball2" src="ball.png" alt="ball">  
</div>
<script>
//声明脑袋的默认偏移
var offsetLeft = test.offsetLeft;
var offsetTop = test.offsetTop;
//声明左眼夹角a1、右眼夹角a2
var a1,a2;
//声明左眼圆心(X1,Y1)、右眼圆心(X2,Y2)
var X1 = 38,Y1 = 72,X2 = 106,Y2 = 68;
//声明半径
var R = 12;
document.onmousemove = function(e){
  e = e || event;
  //获取鼠标坐标
  var x = e.clientX;
  var y = e.clientY;
  //更新夹角a1、a2
  a1 = Math.atan2(x-X1-offsetLeft,y-Y1-offsetTop);
  a2 = Math.atan2(x-X2-offsetLeft,y-Y2-offsetTop);
  //更新左眼、右眼的left、top值
  ball1.style.left = R*Math.sin(a1) + X1 -10 + 'px';
  ball1.style.top = R*Math.cos(a1) + Y1 -10+ 'px';
  ball2.style.left = R*Math.sin(a2) + X2 -10 + 'px';
  ball2.style.top = R*Math.cos(a2) + Y2 -10 + 'px';
}
</script>
</body>
</html>

苹果菜单

苹果菜单中也存在着鼠标跟随运动,与鼠标距离越近的菜单项的宽高越大,越远则宽高越小

javascript鼠标跟随运动3种效果(眼球效果,苹果菜单,方向跟随)

鼠标坐标可以通过mousemove事件中的clientX和clientY获得。菜单项的坐标其实是已知项。而鼠标坐标与菜单项的距离就是要求的距离,而距离与菜单项的宽高成反比

[注意]不能够将元素的自定义属性命名为x,因为x已经被浏览器使用

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
body{margin: 0;}
#test{position: absolute;bottom:0;width: 100%;text-align: center;}
img{width: 64px;height: 64px;}
</style>
</head>
<body>
<div id="test">
  <img id="img1" src="img/1.png">
  <img src="img/2.png">
  <img src="img/3.png">
  <img src="img/4.png">
  <img src="img/5.png"> 
</div>
<script>
//声明菜单项的宽高值
var offsetWidth = img1.offsetWidth;
var offsetHeight = img1.offsetHeight;
//声明外层盒子的left、top值
var offsetLeft = test.offsetLeft;
var offsetTop = test.offsetTop;
//获取菜单项
var imgs = test.getElementsByTagName('img');
document.onmousemove = function(e){
  e = e || event;
  //更新鼠标位置
  var x = e.clientX;
  var y = e.clientY;
  for(var i = 0; i < imgs.length; i++){
    //获取菜单项的坐标
    imgs[i].x0= imgs[i].offsetLeft+offsetLeft+imgs[i].offsetWidth/2;
    imgs[i].y0 = imgs[i].offsetTop + offsetTop + imgs[i].offsetHeight/2;
    //更新鼠标与菜单项的距离
    imgs[i].len =Math.sqrt((x-imgs[i].x0)*(x-imgs[i].x0) + (y-imgs[i].y0)*(y-imgs[i].y0));
    //限制范围
    if(imgs[i].len > 150){
      imgs[i].len = 150;
    }
    //更新菜单项的宽高
    imgs[i].style.width = (1-imgs[i].len/300)*2*offsetWidth + 'px';
    imgs[i].style.height = (1-imgs[i].len/300)*2*offsetHeight + 'px';
    
  }
}
</script>
</body>
</html>

方向跟随

有许多网页都有方向跟随的效果。鼠标从哪个方向移入,元素就跟着从哪个方向移入。鼠标从哪个方向移出,类似地,元素也跟着从哪个方向移出

移入移出的运动效果使用匀速直线运动即可,这里主要需要判断方向

javascript鼠标跟随运动3种效果(眼球效果,苹果菜单,方向跟随)

由示意图中所示,可以把一个正方形的元素分成(上-右、上-左、左-上、左-下、下-右、下-左、右-上、右-下)这8个部分,每个部分是一个等腰直角三角形,当元素进入某个区域时,横线前面的方向就表示元素的方向

假设正方形的中心坐标为(x0,y0),动态元素(move)进入时的坐标为(x,y),以这两个坐标组成的直线与水平正方向的直线的夹角作为基准角,假设为a,则通过确定夹角a的范围,可以确定动态元素(move)进入的方向

-45<a<45时,进入方向为右
45<a<135时,进入方向为上
a>135或a<-135时,进入方向为左
-135<a<-45时,进入方向为下

确定好动态元素(move)进入的方向后,需要根据方向,将动态元素(move)瞬间变换到对应的位置。然后,动态元素(move)进行匀速直线运动,最终停止在与静态元素(test)重合的位置

动态元素(move)移出静态元素(test)的范围时,要注意的是,并不会触发静态元素(test)的mouseout事件。因为,此时鼠标一直处于动态元素(move)上。所以,触发的是动态元素(move)的mouseout事件

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
#box{overflow: hidden;position: relative;left: 100px;top: 100px;height: 100px;width: 300px;}
.test{width: 100px;height: 100px;position: absolute;font:20px/100px '宋体';text-align: center;} 
</style>
</head>
<body>
<div id="box">
  <div class="test" style="top: 0px;left: 0px;background-color: pink;">1</div>
  <div class="test" style="top: 0px;left: 100px;background-color: lightcoral;">2</div>
  <div class="test" style="top: 0px;left: 200px;background-color: lightgreen;">3</div> 
  <div id="move" style="width: 100px;height: 100px;background-color: lightblue;position: absolute;top: -100px;left: -100px;"></div> 
</div>
<script>
var tests = box.getElementsByTagName('div');
for(var i = 0; i < tests.length; i++){
  tests[i].onmouseover = fn;
}
//鼠标移出动态元素(move)时,再将fn()函数置于所有静态元素上
move.onmouseout = fn;
function fn(e){
  e = e || event;
  //阻止冒泡
  if(e.stopPropagation){
    e.stopPropagation();
  }else{
    e.cancelBubble = true;
  }
  for(var i = 0; i < tests.length; i++){
    tests[i].onmouseover = fn;
  }
  var _this = this;
  //鼠标移入动态元素(move)时,将静态元素上的mouseover事件置空
  move.onmouseover = function(){
    move.innerHTML = _this.innerHTML;
    _this.onmouseover = null;
  }
  //声明坐标
  var x = e.clientX;
  var y = e.clientY;
  //声明静态元素(test)左上角坐标(相对于父级)
  var x11 = this.offsetLeft;
  var y11 = this.offsetTop;  
   //声明静态元素(test)中心点坐标(相对于父级)
  var x10 = x11 + this.offsetWidth/2;
  var y10 = y11 + this.offsetHeight/2;  
  //声明静态元素(test)左上角坐标(相对于文档)
  var x21 = this.parentNode.offsetLeft + x11;
  var y21 = this.parentNode.offsetTop + y11;
  //声明静态元素(test)中心点坐标(相对于文档)
  var x20 = x21 + this.offsetWidth/2;
  var y20 = y21 + this.offsetHeight/2;
  //声明静态元素宽高
  var height = this.offsetHeight;
  var width = this.offsetWidth;
  //声明并计算夹角
  var a = Math.atan2(y20-y,x-x20)*180/Math.PI;
  //声明并计算方向
  var dir;
  if(a > -45 && a < 45){
    dir = 'right';
  }else if(a > 45 && a < 135){
    dir = 'top';
  }else if(a > -135 && a < 45){
    dir = 'bottom';
  }else{
    dir = 'left';
  }
  //鼠标移入时
  if(e.type == 'mouseover'){
    //更新动态元素(move)的初始位置
    //移动动态元素(move)直到完全覆盖静态元素(test)
    if(dir == 'right'){
      move.style.left = x10 + width/2 + 'px';
      move.style.top = y10 - height/2 + 'px';
      fnMove(move,'left',x11)
    }else if(dir == 'top'){
      move.style.left = x10 - width/2 + 'px';
      move.style.top = y10 - height/2 - height + 'px'; 
      fnMove(move,'top',y11)
    }else if(dir == 'left'){
      move.style.left = x10 - width/2 - width + 'px';
      move.style.top = y10 - height/2 + 'px';
      fnMove(move,'left',x11)     
    }else{
      move.style.left = x10 - width/2 + 'px';
      move.style.top = y10 - height/2 + height + 'px'; 
      fnMove(move,'top',y11)    
    }     
  }
  if(e.type == 'mouseout'){
    //鼠标移出时
    if(dir == 'right'){
      fnMove(move,'left',x11 + width);
    }else if(dir == 'top'){
      fnMove(move,'top',y11 - height);
    }else if(dir == 'left'){
      fnMove(move,'left',x11 - width);
    }else{
      fnMove(move,'top',y11 + height);
    }     
  }
}
function getCSS(obj,style){
  if(window.getComputedStyle){
    return getComputedStyle(obj)[style];
  }
  return obj.currentStyle[style];
}
function fnMove(obj,attr,target){
  var H = obj.offsetHeight;
  if(obj.timer) return;
  var cur = parseFloat(getCSS(obj,attr));
  if(target > cur){
    var step = H/4;
  }else{
    var step = -H/4;
  }
  obj.timer = setInterval(function(){
    cur = parseFloat(getCSS(obj,attr));
    cur = cur + step;
    if((cur -target) * step >= 0){
      cur = target; 
    }
      obj.style[attr] = cur + 'px'; 
    if(cur == target){
      clearInterval(obj.timer);
      obj.timer = 0;
    }
  },20);
} 
</script>  
</body>
</html>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
一个js的tab切换效果代码[代码分离]
Apr 11 Javascript
ASP.NET jQuery 实例15 通过控件CustomValidator验证CheckBoxList
Feb 03 Javascript
复制js对象方法(详解)
Jul 08 Javascript
使用jQuery插件创建常规模态窗口登陆效果
Aug 23 Javascript
jquery 日期控件datepicker属性详细解析
Nov 08 Javascript
JavaScript使用指针操作实现约瑟夫问题实例
Apr 07 Javascript
javascript实现滑动解锁功能
Mar 22 Javascript
jQuery遮罩层实例讲解
May 11 jQuery
JavaScript简单拖拽效果(1)
May 17 Javascript
vue--点击当前增加class,其他删除class的方法
Sep 15 Javascript
jquery.param()实现数组或对象的序列化方法
Oct 08 jQuery
vue实现图片按比例缩放问题操作
Aug 11 Javascript
简单理解vue中track-by属性
Oct 26 #Javascript
javascript iframe跨域详解
Oct 26 #Javascript
JS日期对象简单操作(获取当前年份、星期、时间)
Oct 26 #Javascript
jQuery的ready方法实现原理分析
Oct 26 #Javascript
JavaScript中省略元素对数组长度的影响
Oct 26 #Javascript
BootStrap tab选项卡使用小结
Aug 09 #Javascript
Bootstrap按钮功能之查询按钮和重置按钮
Oct 26 #Javascript
You might like
ThinkPHP静态缓存简单配置和使用方法详解
2016/03/23 PHP
phpmailer绑定邮箱的实现方法
2016/12/01 PHP
PHP下载远程图片的几种方法总结
2017/04/07 PHP
基于mootools插件实现遮罩层新手引导
2012/05/24 Javascript
JS判断页面加载状态以及添加遮罩和缓冲动画的代码
2012/10/11 Javascript
JavaScript更改原始对象valueOf的方法
2015/03/19 Javascript
javascript操作表格排序实例分析
2015/05/06 Javascript
jQuery幻灯片特效代码分享--鼠标滑过按钮时切换(2)
2020/11/18 Javascript
node.js回调函数之阻塞调用与非阻塞调用
2015/11/13 Javascript
基于匀速运动的实例讲解(侧边栏,淡入淡出)
2017/10/17 Javascript
react中fetch之cors跨域请求的实现方法
2018/03/14 Javascript
js动态设置select下拉菜单的默认选中项实例
2018/08/21 Javascript
关于vue项目中搜索节流的实现代码
2019/09/17 Javascript
微信小程序实现弹框效果
2020/05/26 Javascript
python使用cookie库操保存cookie详解
2014/03/03 Python
Python实现在线程里运行scrapy的方法
2015/04/07 Python
Python list操作用法总结
2015/11/10 Python
Python实现新浪博客备份的方法
2016/04/27 Python
Django中STATIC_ROOT和STATIC_URL及STATICFILES_DIRS浅析
2018/05/08 Python
Python 修改列表中的元素方法
2018/06/26 Python
Python设计模式之备忘录模式原理与用法详解
2019/01/15 Python
Django实现auth模块下的登录注册与注销功能
2019/10/10 Python
Python如何基于smtplib发不同格式的邮件
2019/12/30 Python
用python批量下载apk
2020/12/29 Python
HTML5的Geolocation地理位置定位API使用教程
2016/05/12 HTML / CSS
iHerb中文官网:维生素、保健品和健康产品
2018/11/01 全球购物
linux面试题参考答案(1)
2016/01/22 面试题
Servlet面试题库
2015/07/18 面试题
奥巴马当选演讲稿
2014/09/10 职场文书
2015秋季小学开学寄语
2015/05/27 职场文书
2016年“6.26”禁毒宣传月系列活动总结
2016/04/05 职场文书
个人销售励志奋斗口号
2019/12/05 职场文书
SpringMVC 整合SSM框架详解
2021/08/30 Java/Android
剑指Offer之Java算法习题精讲二叉树的构造和遍历
2022/03/21 Java/Android
vue3使用vuedraggable实现拖拽功能
2022/04/06 Vue.js
Python中生成随机数据安全性、多功能性、用途和速度方面进行比较
2022/04/14 Python