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 相关文章推荐
ImageZoom 图片放大镜效果(多功能扩展篇)
Apr 14 Javascript
javascript string字符串优化问题
Jul 31 Javascript
JS中如何比较两个Json对象是否相等实例代码
Jul 13 Javascript
详解jQuery简单的表格应用
Dec 16 Javascript
教你用十行node.js代码读取docx的文本
Mar 08 Javascript
详解JS获取HTML DOM元素的8种方法
Jun 17 Javascript
vue select二级联动第二级默认选中第一个option值的实例
Jan 10 Javascript
浅谈webpack打包之后的文件过大的解决方法
Mar 07 Javascript
通过一次报错详细谈谈Point事件
May 17 Javascript
JS计算两个数组的交集、差集、并集、补集(多种实现方式)
May 21 Javascript
React中获取数据的3种方法及优缺点
Feb 18 Javascript
js实现缓动动画
Nov 25 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制作新闻系统的思路
2006/10/09 PHP
十天学会php(1)
2006/10/09 PHP
使用php+Ajax实现唯一校验实现代码[简单应用]
2011/11/29 PHP
PHP+MySQL投票系统的设计和实现分享
2012/09/23 PHP
PHP5.0 TIDY_PARSE_FILE缓冲区溢出漏洞的解决方案
2018/10/14 PHP
HTML node相关的一些资料整理
2010/01/01 Javascript
JS 自定义函数缺省值的设置方法
2010/05/05 Javascript
javascript innerHTML使用分析
2010/12/03 Javascript
jQuery Tools tab使用介绍
2012/07/14 Javascript
JavaScript 参数中的数组展开 [译]
2012/09/21 Javascript
javascript打印大全(打印页面设置/打印预览代码)
2013/03/29 Javascript
使用JavaScript 实现对象 匀速/变速运动的方法
2013/05/08 Javascript
Angular指令封装jQuery日期时间插件datetimepicker实现双向绑定示例
2017/01/22 Javascript
判断横屏竖屏(三种)
2017/02/13 Javascript
nodejs根据ip数组在百度地图中进行定位
2017/03/06 NodeJs
canvas基础绘制-绚丽倒计时的实例
2017/09/17 Javascript
phantomjs导出html到pdf的方法总结
2017/10/19 Javascript
JS使用H5实现图片预览功能
2019/09/30 Javascript
vue-router 2.0 跳转之router.push()用法说明
2020/08/12 Javascript
javascript中导出与导入实现模块化管理教程
2020/12/03 Javascript
python编写暴力破解FTP密码小工具
2014/11/19 Python
Python通过命令开启http.server服务器的方法
2017/11/04 Python
PyQt5每天必学之事件与信号
2018/04/20 Python
python实现一个猜拳游戏
2020/04/05 Python
Python 实现将某一列设置为str类型
2020/07/14 Python
Superdry极度干燥美国官网:英国制造的服装品牌
2018/11/13 全球购物
抽象类和接口的区别
2012/09/19 面试题
大学生就业推荐信范文
2013/11/29 职场文书
中学生打架检讨书
2014/02/10 职场文书
党员违纪检讨书
2014/02/18 职场文书
财政专业大学生职业生涯规划书
2014/09/17 职场文书
2014年团队工作总结
2014/11/24 职场文书
结婚保证书(三从四德)
2015/02/26 职场文书
大学团日活动总结书
2015/05/11 职场文书
《1942》观后感
2015/06/08 职场文书
强烈推荐:小学生:暑假作息时间表(值得收藏)
2019/07/09 职场文书