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 相关文章推荐
一个刚完成的layout(拖动流畅,不受iframe影响)
Aug 17 Javascript
jQuery + Flex 通过拖拽方式动态改变图片的代码
Aug 03 Javascript
jquery图片滚动放大代码分享(2)
Aug 28 Javascript
js获取鼠标点击的对象,点击另一个按钮删除该对象的实现代码
May 13 Javascript
干货!教大家如何选择Vue和React
Mar 13 Javascript
关于Vue实现组件信息的缓存问题
Aug 23 Javascript
使用javascript函数编写简单银行取钱存钱流程
May 26 Javascript
React传值 组件传值 之间的关系详解
Aug 26 Javascript
Vue-drag-resize 拖拽缩放插件的使用(简单示例)
Dec 04 Javascript
JS数组的高级使用方法示例小结
Mar 14 Javascript
原生JavaScript写出Tabs标签页的实例代码
Jul 20 Javascript
DWR内存兼容及无法调用问题解决方案
Oct 16 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
Symfony实现行为和模板中取得request参数的方法
2016/03/17 PHP
PHP常用函数之格式化时间操作示例
2019/10/21 PHP
IE6与IE7中,innerHTML获取param的区别
2009/03/15 Javascript
详解AngularJS的通信机制
2015/06/18 Javascript
包含中国城市的javascript对象实例
2015/08/03 Javascript
javascript实现支持移动设备画廊
2015/08/24 Javascript
js的form表单提交url传参数(包含+等特殊字符)的两种解决方法
2016/05/25 Javascript
JS检测页面中哪个HTML标签触发点击事件的方法
2016/06/17 Javascript
详解Angular.js数据绑定时自动转义html标签及内容
2017/03/30 Javascript
微信小程序联网请求的轮播图
2017/07/07 Javascript
详解Nodejs内存治理
2018/05/13 NodeJs
Angular搜索场景中使用rxjs的操作符处理思路
2018/05/30 Javascript
vue2.0 中使用transition实现动画效果使用心得
2018/08/13 Javascript
浅谈vue项目4rs vue-router上线后history模式遇到的坑
2018/09/27 Javascript
vue实现菜单切换功能
2019/05/08 Javascript
Vue中的循环及修改差值表达式的方法
2019/08/29 Javascript
Python中input与raw_input 之间的比较
2017/08/20 Python
Python设计模式之门面模式简单示例
2018/01/09 Python
python使用time、datetime返回工作日列表实例代码
2019/05/09 Python
python下载库的步骤方法
2019/10/12 Python
Python3.7下安装pyqt5的方法步骤(图文)
2020/05/12 Python
Python的Django框架实现数据库查询(不返回QuerySet的方法)
2020/05/19 Python
python如何输出反斜杠
2020/06/18 Python
Python内置方法和属性应用:反射和单例(推荐)
2020/06/19 Python
keras的backend 设置 tensorflow,theano操作
2020/06/30 Python
美国在线鞋类零售商:LifeStride
2019/06/09 全球购物
乌克兰第一的珠宝网上商店:Gold.ua
2019/11/29 全球购物
Jacques Lemans德国:奥地利钟表品牌
2019/12/26 全球购物
施华洛世奇新加坡官网:SWAROVSKI新加坡
2020/10/06 全球购物
幼儿园教师备课制度
2014/01/12 职场文书
三好学生演讲稿范文
2014/04/26 职场文书
中班下学期个人总结
2015/02/12 职场文书
学术会议领导致辞
2015/07/29 职场文书
2015年终个人政治思想工作总结
2015/11/24 职场文书
2016教师党员学习心得体会
2016/01/21 职场文书
使用MybatisPlus打印sql语句
2022/04/22 SQL Server