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 相关文章推荐
HTML中不支持静态Expando的元素的问题
Mar 08 Javascript
解析Jquery中如何把一段html代码动态写入到DIV中(实例说明)
Jul 09 Javascript
一个不错的字符串转码解码函数(自写)
Jul 31 Javascript
jquery实现可拖拽弹出层特效
Jan 04 Javascript
详解AngularJS的通信机制
Jun 18 Javascript
JavaScript实现获取某个元素相邻兄弟节点的prev与next方法
Jan 25 Javascript
js实现上传图片及时预览
May 07 Javascript
js实现数组去重方法及效率?Ρ? target=
Feb 14 Javascript
Bootstrap Table使用整理(四)之工具栏
Jun 09 Javascript
JavaScript引用类型Object常见用法实例分析
Aug 08 Javascript
详解Webstorm 下的Angular2.0开发之路(图文)
Dec 06 Javascript
vue中实现高德定位功能
Dec 03 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 和 MySQL 基础教程(一)
2006/10/09 PHP
详解PHP中strlen和mb_strlen函数的区别
2014/03/07 PHP
浅谈php中的访问修饰符private、protected、public的作用范围
2016/11/20 PHP
PHP实现的无限分类类库定义与用法示例【基于thinkPHP】
2018/08/06 PHP
js Array对象的扩展函数代码
2013/04/24 Javascript
jQuery 如何先创建、再修改、后添加DOM元素
2014/05/20 Javascript
JavaScript中使用Object.prototype.toString判断是否为数组
2015/04/01 Javascript
JS区分浏览器页面是刷新还是关闭
2016/04/17 Javascript
jquery实现图片上传前本地预览功能
2016/05/10 Javascript
node.js发送邮件email的方法详解
2017/01/06 Javascript
async/await与promise(nodejs中的异步操作问题)
2017/03/03 NodeJs
jQuery中each方法的使用详解
2018/03/18 jQuery
vue中keep-alive的用法及问题描述
2018/05/15 Javascript
js中split()方法得到的数组长度问题
2018/07/19 Javascript
在NPM发布自己造的轮子的方法步骤
2019/03/09 Javascript
Node.js使用supervisor进行开发中调试的方法
2019/03/26 Javascript
angularjs请求数据的方法示例
2019/08/06 Javascript
javascript合并两个数组最简单的实现方法
2019/09/14 Javascript
使用python实现http及ftp服务进行数据传输的方法
2018/10/26 Python
python 画3维轨迹图并进行比较的实例
2019/12/06 Python
Python CSV文件模块的使用案例分析
2019/12/21 Python
python json 递归打印所有json子节点信息的例子
2020/02/27 Python
python zip,lambda,map函数代码实例
2020/04/04 Python
解决更改AUTH_USER_MODEL后出现的问题
2020/05/14 Python
如何用tempfile库创建python进程中的临时文件
2021/01/28 Python
css3之UI元素状态伪类选择器实例演示
2017/08/11 HTML / CSS
如何用border-image实现文字气泡边框的示例代码
2020/01/21 HTML / CSS
浅析HTML5中header标签的用法
2016/06/24 HTML / CSS
平面设计求职信
2014/03/10 职场文书
销售目标责任书
2014/07/23 职场文书
单位一把手群众路线四风问题整改措施
2014/09/25 职场文书
学校党委干部个人对照检查材料思想汇报
2014/10/09 职场文书
经理岗位职责
2015/02/02 职场文书
北京天坛导游词
2015/02/12 职场文书
python解决12306登录验证码的实现
2021/04/18 Python
pandas进行数据输入和输出的方法详解
2022/03/23 Python