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 相关文章推荐
xmlHTTP实例
Oct 24 Javascript
比较搞笑的js陷阱题
Feb 07 Javascript
JQuery对checkbox操作 (循环获取)
May 20 Javascript
深入理解JavaScript系列(11) 执行上下文(Execution Contexts)
Jan 15 Javascript
jQuery取得select选择的文本与值的示例
Dec 09 Javascript
jquery操作HTML5 的data-*的用法实例分享
Aug 17 Javascript
JS实现一个按钮的方法
Feb 05 Javascript
jquery在ie7下选择器的问题导致append失效的解决方法
Jan 10 Javascript
javascript实现九宫格相加数值相等
May 28 Javascript
谈谈PHP中相对路径的问题与绝对路径的使用
Aug 16 Javascript
AngularJS实时获取并显示密码的方法
Feb 06 Javascript
vue商城中商品“筛选器”功能的实现代码
Jul 01 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+javascript模拟Matrix画面
2006/10/09 PHP
php变量范围介绍
2012/10/15 PHP
php的数组与字符串的转换函数整理汇总
2013/07/18 PHP
PHP连接MYSQL数据库实例代码
2016/01/20 PHP
再谈querySelector和querySelectorAll的区别与联系
2012/04/20 Javascript
js/jQuery对象互转(快速操作dom元素)
2013/02/04 Javascript
JavaScript异步编程Promise模式的6个特性
2014/04/03 Javascript
jQuery之Deferred对象详解
2014/09/04 Javascript
使用AngularJS2中的指令实现按钮的切换效果
2017/03/27 Javascript
jQuery判断网页是否已经滚动到浏览器底部的实现方法
2017/10/27 jQuery
Node.Js中实现端口重用原理详解
2018/05/03 Javascript
在vue中更换字体,本地存储字体非引用在线字体库的方法
2018/09/28 Javascript
JS高阶函数原理与用法实例分析
2019/01/15 Javascript
详解小程序毫秒级倒计时(适用于拼团秒杀功能)
2019/05/05 Javascript
100行代码实现vue表单校验功能(小白自编)
2019/11/19 Javascript
jQuery实现移动端扭蛋机抽奖
2020/11/08 jQuery
python3 实现的人人影视网站自动签到
2016/06/19 Python
Numpy中矩阵matrix读取一列的方法及数组和矩阵的相互转换实例
2018/07/02 Python
Caffe均值文件mean.binaryproto转mean.npy的方法
2018/07/09 Python
python 3.6.5 安装配置方法图文教程
2018/09/18 Python
解决django前后端分离csrf验证的问题
2019/02/03 Python
Python列表list常用内建函数实例小结
2019/10/22 Python
Python编译成.so文件进行加密后调用的实现
2019/12/23 Python
Python sys模块常用方法解析
2020/02/20 Python
Python并发请求下限制QPS(每秒查询率)的实现代码
2020/06/05 Python
Python+OpenCV图像处理——实现直线检测
2020/10/23 Python
有关HTML5中背景音乐的自动播放功能
2017/10/16 HTML / CSS
巴黎一票通:The Paris Pass
2018/02/10 全球购物
越南母婴用品购物网站:Kids Plaza
2020/04/09 全球购物
将相和教学反思
2014/02/04 职场文书
老师对学生的评语
2014/04/18 职场文书
支部书记四风问题自我剖析材料
2014/09/29 职场文书
2014年党的群众路线整改措施思想汇报
2014/10/12 职场文书
检讨书格式
2019/04/25 职场文书
TensorFlow的自动求导原理分析
2021/05/26 Python
python APScheduler执行定时任务介绍
2022/04/19 Python