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实现雪花飘落效果
Aug 26 Javascript
cookie的secure属性详解
Apr 08 Javascript
jQuery ui实现动感的圆角渐变网站导航菜单效果代码
Aug 26 Javascript
JavaScript中iframe实现局部刷新的几种方法汇总
Jan 06 Javascript
ASP.NET jquery ajax传递参数的实例
Nov 02 Javascript
简单理解Vue中的nextTick方法
Jan 30 Javascript
基于mpvue的小程序项目搭建的步骤
May 22 Javascript
示例vue 的keep-alive缓存功能的实现
Dec 13 Javascript
Vue.js中该如何自己维护路由跳转记录
May 19 Javascript
使用VueRouter的addRoutes方法实现动态添加用户的权限路由
Jun 03 Javascript
JavaScript实现世界各地时间显示
Sep 07 Javascript
jdk1.8+vue elementui实现多级菜单功能
Sep 24 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
国外比较好的几个的Php开源建站平台小结
2010/04/22 PHP
PHP中的多种加密技术及代码示例解析
2016/10/20 PHP
php中preg_replace正则替换用法分析【一次替换多个值】
2017/01/17 PHP
js 省地市级联选择
2010/02/07 Javascript
Javascript 自适应高度的Tab选项卡
2011/04/05 Javascript
页面使用密码保护代码
2013/04/10 Javascript
用js实现小球的自由移动代码
2013/04/22 Javascript
利用cookie记住背景颜色示例代码
2013/11/04 Javascript
JS实现图片平面旋转的方法
2016/03/01 Javascript
实例讲解Jquery中隐藏hide、显示show、切换toggle的用法
2016/05/13 Javascript
js操作数据库实现注册和登陆的简单实例
2016/05/26 Javascript
AngularJS实现数据列表的增加、删除和上移下移等功能实例
2016/09/05 Javascript
Vue.js中用v-bind绑定class的注意事项
2016/12/13 Javascript
Vue.js原理分析之observer模块详解
2017/02/17 Javascript
BootstrapValidator实现注册校验和登录错误提示效果
2017/03/10 Javascript
vue几个常用跨域处理方式介绍
2018/02/07 Javascript
Node.JS循环删除非空文件夹及子目录下的所有文件
2018/03/12 Javascript
Vue仿支付宝支付功能
2018/05/25 Javascript
vue中vee validate表单校验的几种基本使用
2018/06/25 Javascript
Vue.Draggable拖拽功能的配置使用方法
2020/07/29 Javascript
three.js 将图片马赛克化的示例代码
2020/07/31 Javascript
python映射列表实例分析
2015/01/26 Python
Python2.7编程中SQLite3基本操作方法示例
2017/08/09 Python
基于Python log 的正确打开方式
2018/04/28 Python
Django添加sitemap的方法示例
2018/08/06 Python
Python unittest 简单实现参数化的方法
2018/11/30 Python
Python变量类型知识点总结
2019/02/18 Python
Django Form 实时从数据库中获取数据的操作方法
2019/07/25 Python
Python利用matplotlib绘制散点图的新手教程
2020/11/05 Python
Pytorch - TORCH.NN.INIT 参数初始化的操作
2021/02/27 Python
家长评语大全
2014/01/22 职场文书
演讲稿格式范文
2014/05/19 职场文书
法学专业求职信
2014/07/15 职场文书
幼儿教师辞职信范文
2015/03/02 职场文书
2015年工商局个人工作总结
2015/07/23 职场文书
动画「进击的巨人」第86话播出感谢绘公开
2022/03/21 日漫