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 相关文章推荐
jquery中交替点击事件toggle方法的使用示例
Dec 08 Javascript
javascript字符串循环匹配实例分析
Jul 17 Javascript
原生js与jQuery实现简单的tab切换特效对比
Jul 30 Javascript
使用Curl命令查看请求响应时间方法
Nov 04 Javascript
jQuery Ajax全解析
Feb 13 Javascript
使用Vue完成一个简单的todolist的方法
Dec 01 Javascript
bootstrap-table.js扩展分页工具栏(增加跳转到xx页)功能
Dec 28 Javascript
vue bus全局事件中心简单Demo详解
Feb 26 Javascript
create-react-app构建项目慢的解决方法
Mar 14 Javascript
在SSM框架下用laypage和ajax实现分页和数据交互的方法
Sep 27 Javascript
layui数据表格 table.render 报错的解决方法
Sep 29 Javascript
vue radio单选框,获取当前项(每一项)的value值操作
Sep 10 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
php读取数据库信息的几种方法
2008/05/24 PHP
php检测图片木马多进制编程实践
2013/04/11 PHP
PHP5各个版本的新功能和新特性总结
2014/03/16 PHP
javascript数组与php数组的地址传递及值传递用法实例
2015/01/22 PHP
PHP闭包函数传参及使用外部变量的方法
2016/03/15 PHP
Zend Framework使用Zend_Loader组件动态加载文件和类用法详解
2016/12/09 PHP
IE不出现Flash激活框的小发现的js实现方法
2007/09/07 Javascript
jQuery.ajax 用户登录验证代码
2010/10/29 Javascript
颜色选择器 Color Picker,IE,Firefox,Opera,Safar
2010/11/25 Javascript
JS格式化数字金额用逗号隔开保留两位小数
2013/10/18 Javascript
jquery中交替点击事件的实现代码
2014/02/14 Javascript
JavaScript表单通过正则表达式验证电话号码
2014/03/14 Javascript
JavaScript数组深拷贝和浅拷贝的两种方法
2014/04/16 Javascript
nodejs 整合kindEditor实现图片上传
2015/02/03 NodeJs
JavaScript中0和&quot;&quot;比较引发的问题
2016/05/26 Javascript
js多个物体运动功能实例分析
2016/12/20 Javascript
three.js搭建室内场景教程
2018/12/30 Javascript
Node.js对MongoDB进行增删改查操作的实例代码
2019/04/18 Javascript
Cpy和Python的效率对比
2015/03/20 Python
Python 爬虫学习笔记之单线程爬虫
2016/09/21 Python
python爬虫之线程池和进程池功能与用法详解
2018/08/02 Python
使用Python获取网段IP个数以及地址清单的方法
2018/11/01 Python
python将视频转换为全字符视频
2019/04/26 Python
让你Python到很爽的加速递归函数的装饰器
2019/05/26 Python
Python获取命令实时输出-原样彩色输出并返回输出结果的示例
2019/07/11 Python
python 实现手机自动拨打电话的方法(通话压力测试)
2019/08/08 Python
Python hashlib加密模块常用方法解析
2019/12/18 Python
Flask 上传自定义头像的实例详解
2020/01/09 Python
python使用bs4爬取boss直聘静态页面
2020/10/10 Python
用CSS3的box-reflect来制作倒影效果
2016/11/15 HTML / CSS
东芝官网商城:还原日式美学,打造美好生活
2018/12/27 全球购物
测绘工程本科生求职信
2013/10/10 职场文书
教师作风整改措施思想汇报
2014/10/12 职场文书
感恩老师主题班会
2015/08/12 职场文书
诚实守信主题班会
2015/08/13 职场文书
将MySQL的表数据全量导入clichhouse库中
2022/03/21 MySQL