JavaScript实现类似拉勾网的鼠标移入移出效果


Posted in Javascript onOctober 27, 2016

先上效果图(gif自己录制的,有点难看抱歉,工具licecap)

JavaScript实现类似拉勾网的鼠标移入移出效果 

实现思路

 HTML结构

<ul>
    <li>
      <div class="bg">
        <p>JS</p>
      </div>
    </li>
    .....
  </ul>

    li作为鼠标移入(mouseenter)和鼠标移出(mouseleave)的载体。

    div作为动画执行的载体。

CSS

    div采用absolute定位,通过top、left改变它的位置。

    由于div的top、left可能会超出li的大小,所以要设置li的overflow:hidden;

JS

    1、采用JS操纵CSS3 transition动画

    2、如何判断鼠标移入移除的方向

鼠标坐标的相关知识

MouseEvent对象

下面介绍几个MouseEvent中坐标的相关知识:

    (clientX, clientY): 以可视区域为参考系的坐标。

    (pageX, pageY): 以整个页面(包括滚动条卷出的区域)为参考系的坐标。

    (screenX, screenY): 以你的电脑屏幕为参考系的坐标。

    获取某个元素内部的坐标

function pointTo(element, e) {
    var elementBox = element.getBoundingClientRect();
    return {
      x: e.clientX - elementBox.left,
      y: e.clientY - elementBox.top
    };
  }

    计算元素左上角的坐标

function startPoint(element){
    var x = 0,y = 0;
    while(element != null) {
      x += element.offsetLeft;
      y += element.offsetTop;
      element = element.offsetParent;
    }
    return {
      x: x,
      y: y
    }
  }

    获取元素的宽度和高度(不要认为是width和height 新手特别容易犯错)

offsetHeight与offsetWidth

简单的封装一下CSS3 transition动画

/* options参数: obj: 运动的对象 speed: 运动的持续时间(可选) changeStyle: 改变的属性,这里可能多个,所以采用函数的方式(可选) callback: 回调函数(可选) */
  function animation(options){
    if(!options.obj) {
      return false;
    }
    //设置默认持续时间
    options.speed = options.speed || '.5s';
    options.obj.style.transition = "all " + options.speed + " ease-in-out";

    options.changeStyle.call(options.obj);

    var flag = false;
    options.obj.addEventListener('transitionend',function(){
      //这里主要由于transitionend在每个属性的动画执行完多会走一遍,所以我们要让它只执行一次。
      if(!flag) {

        options.callback && options.callback();
      }
    },false);
  }

如何确定方向

这里要用到数学中的正切相关的概念,我自己画了一张图,不知道你们能不能看特明白:(奇丑。。。)

JavaScript实现类似拉勾网的鼠标移入移出效果 

得到元素的运动方向

function getDirection(element,startPoint,pagePoint){
    var halfWidth = element.offsetWidth / 2,halfHeight = element.offsetHeight / 2;
    //得到中心点
    var center = {
      x: startPoint.x + halfWidth,
      y: startPoint.y + halfHeight
    }
    //得到鼠标偏离中心点的距离
    var disX = pagePoint.x - center.x;
    var disY = pagePoint.y - center.y;
    if(disY < 0 && Math.abs(disY / disX) >= 1) {
      //上方
      return 1;
    }
    else if(disY > 0 && Math.abs(disY / disX) >= 1) {
      //下
      return 2;
    }
    else if(disX < 0 && Math.abs(disY / disX) < 1) {
      //左
      return 3;
    }
    else {
      //右
      return 4;
    }
  }

启动事件的代码,有注释

/* options中的参数: 触发事件的载体: targetElement 执行动画的载体: animationElement */
  function HoverAction(options) {
    if(!options.targetElement || !options.animationElement) {
      return false;
    }
    this.targetElement = options.targetElement;
    this.animationElement = options.animationElement;
    this.timeId = null;
    this.speed = "0.3s";
  }
  HoverAction.prototype.addEvent = function() {
    //保存this的指向
    var _this = this;
    _this.targetElement.addEventListener('mouseenter',function(e){
      //得到鼠标的坐标
      var point = {
        x: e.pageX,
        y: e.pageY
      }
      console.log(point);
      //获得方向
      var dir = getDirection(_this.targetElement,startPoint(_this.targetElement),point);
      clearTimeout(_this.timeId);
      //取消过渡动画(防止重置动画载体位置时触发过渡效果)
      _this.animationElement.style.transition = "";
      //得到运动的方向,要确定动画载体的开始位置
      switch(dir){
        case 1:
          _this.animationElement.style.top = "-100%";
          _this.animationElement.style.left = "0";
          break;
        case 2:
          _this.animationElement.style.top = "100%";
          _this.animationElement.style.left = "0";
          break;
        case 3:
          _this.animationElement.style.top = "0";
          _this.animationElement.style.left = "-100%";
          break;
        case 4:
          _this.animationElement.style.top = "0";
          _this.animationElement.style.left = "100%";
          break;
      }
      //异步执行
      _this.timeId = setTimeout(function(){
        animation({
          obj: _this.animationElement,
          speed: _this.speed,
          changeStyle: function(){
            this.style.top = "0";
            this.style.left = "0";
          }
        });
      },20);
    },false);
    _this.targetElement.addEventListener('mouseleave',function(e){
      var left,top;
      var point = {
        x: e.pageX,
        y: e.pageY
      }
      clearTimeout(_this.timeId);
      _this.animationElement.style.transition = "";
      var dir = getDirection(_this.targetElement,startPoint(_this.targetElement),point);
      switch(dir) {
        case 1:
          top = '-100%';
          left = '0';
          break;
        case 2:
          top = '100%';
          left = "0";
          break;
        case 3:
          left = "-100%";
          top = "0";
          break;
        case 4:
          left = "100%";
          top = "0";
          break;
      }
      _this.timeId = setTimeout(function(){
        animation({
          obj: _this.animationElement,
          speed: _this.speed,
          changeStyle: function(){
            this.style.top = top;
            this.style.left = left;
          }
        });
      },20);
    },false);

  }

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能有所帮助,如果有疑问大家可以留言交流。

Javascript 相关文章推荐
学习YUI.Ext 第四天--对话框Dialog的使用
Mar 10 Javascript
javascript或asp实现的判断身份证号码是否正确两种验证方法
Nov 26 Javascript
Node.js异步I/O学习笔记
Nov 04 Javascript
JavaScript中判断函数、变量是否存在
Jun 10 Javascript
PHP获取当前页面完整URL的方法
Dec 02 Javascript
JS实现的自动打字效果示例
Mar 10 Javascript
基于jquery实现多选下拉列表
Aug 02 jQuery
引入外部js脚本加载慢与页面白屏问题的解决
Dec 10 Javascript
jQuery实现为table表格动态添加或删除tr功能示例
Feb 19 jQuery
Vue侦测相关api的实现方法
May 22 Javascript
vue实现后台管理权限系统及顶栏三级菜单显示功能
Jun 19 Javascript
vue实现动态给id赋值,点击事件获取当前点击的元素的id操作
Nov 09 Javascript
node.js文件上传处理示例
Oct 27 #Javascript
Vue.js表单控件实践
Oct 27 #Javascript
vue实现可增删查改的成绩单
Oct 27 #Javascript
vuex实现简易计数器
Oct 27 #Javascript
微信小程序  生命周期详解
Oct 27 #Javascript
require.js+vue开发微信上传图片组件
Oct 27 #Javascript
Javascript将字符串日期格式化为yyyy-mm-dd的方法
Oct 27 #Javascript
You might like
excellent!――ASCII Art(由目标图象生成ascii)
2007/02/20 PHP
加强版phplib的DB类
2008/03/31 PHP
PHP 字符串分割和比较
2009/10/06 PHP
PHP时间格式控制符对照表分享
2013/07/23 PHP
在openSUSE42.1下编译安装PHP7 的方法
2015/12/24 PHP
PHP+Ajax实现验证码的实时验证
2016/07/20 PHP
PHP解压ZIP文件到指定文件夹的方法
2016/11/17 PHP
JavaScript使用prototype定义对象类型
2007/02/07 Javascript
extjs 学习笔记 四 带分页的grid
2009/10/20 Javascript
为radio类型的INPUT添加客户端脚本(附加实现JS来禁用onClick事件思路代码)
2010/11/11 Javascript
JS实现匀速运动的代码实例
2013/11/29 Javascript
Javascript中的默认参数详解
2014/10/22 Javascript
js实现交换运动效果的方法
2015/04/10 Javascript
跟我学习javascript的定时器
2015/11/19 Javascript
Node.js中npm常用命令大全
2016/06/09 Javascript
JS日程管理插件FullCalendar简单实例
2017/02/07 Javascript
深入理解ES6学习笔记之块级作用域绑定
2017/08/19 Javascript
10个最优秀的Node.js MVC框架
2017/08/24 Javascript
浅谈gulp创建完整的项目流程
2017/12/20 Javascript
Node对CommonJS的模块规范
2019/11/06 Javascript
[01:15:12]DOTA2上海特级锦标赛主赛事日 - 1 败者组第一轮#4Newbee VS CDEC
2016/03/03 DOTA
python关闭windows进程的方法
2015/04/18 Python
Python数据结构与算法之使用队列解决小猫钓鱼问题
2017/12/14 Python
python实现两个文件合并功能
2018/04/01 Python
通过Py2exe将自己的python程序打包成.exe/.app的方法
2018/05/26 Python
python去重,一个由dict组成的list的去重示例
2019/01/21 Python
python 含子图的gif生成时内存溢出的方法
2019/07/07 Python
CSS3 animation实现逐帧动画效果
2016/06/02 HTML / CSS
ProBikeKit英国:在线公路自行车之家
2017/02/10 全球购物
大学生职业生涯规划书的基本内容
2014/01/06 职场文书
党员自我批评与反省材料
2014/02/10 职场文书
双方协议书
2014/04/22 职场文书
销售岗位职责范本
2014/06/12 职场文书
2014年圣诞节寄语
2014/12/08 职场文书
如何书写授权委托书?
2019/06/25 职场文书
Python使用OpenCV和K-Means聚类对毕业照进行图像分割
2021/06/11 Python