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 相关文章推荐
js自定义事件及事件交互原理概述(二)
Feb 01 Javascript
php与js的区别是什么
Aug 05 Javascript
jQuery中的pushStack实现原理和应用实例
Feb 03 Javascript
Backbone.js框架中简单的View视图编写学习笔记
Feb 14 Javascript
JS基于递归算法实现1,2,3,4,5,6,7,8,9倒序放入数组中的方法
Jan 03 Javascript
vue学习笔记之指令v-text &amp;&amp; v-html &amp;&amp; v-bind详解
May 12 Javascript
Angular4实现动态添加删除表单输入框功能
Aug 11 Javascript
微信小程序websocket实现聊天功能
Mar 30 Javascript
Vue v-for循环之@click点击事件获取元素示例
Nov 09 Javascript
jquery实现直播视频弹幕效果
Feb 25 jQuery
vue实现div单选多选功能
Jul 16 Javascript
javascript实现数字时钟效果
Feb 06 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
一个SQL管理员的web接口
2006/10/09 PHP
PHP 多维数组的排序问题 根据二维数组中某个项排序
2011/11/09 PHP
Thinkphp中volist标签mod控制一定记录的换行BUG解决方法
2014/11/04 PHP
浅析Yii2中GridView常见操作
2016/04/22 PHP
php与阿里云短信接口接入操作案例分析
2020/05/27 PHP
this[] 指的是什么内容 讨论
2007/03/24 Javascript
json 定义
2008/06/10 Javascript
ExtJs使用IFrame的实现代码
2010/03/24 Javascript
在jQuery中使用$而避免跟其它库产生冲突的方法
2015/08/13 Javascript
浅析javascript中的事件代理
2015/11/06 Javascript
javascript设计简单的秒表计时器
2020/09/05 Javascript
js+html5实现canvas绘制网页时钟的方法
2016/05/21 Javascript
各式各样的导航条效果css3结合jquery代码实现
2016/09/17 Javascript
js控制li的隐藏和显示实例代码
2016/10/15 Javascript
JS高级运动实例分析
2016/12/20 Javascript
vue2.0父子组件间传递数据的方法
2018/08/16 Javascript
微信小程序tabbar底部导航
2018/11/05 Javascript
JS/CSS实现字符串单词首字母大写功能
2019/09/03 Javascript
vue 使用鼠标滚动加载数据的例子
2019/10/31 Javascript
[49:20]VG vs TNC Supermajor小组赛B组败者组决赛 BO3 第二场 6.2
2018/06/03 DOTA
Python实现感知机(PLA)算法
2017/12/20 Python
Python实现字典(dict)的迭代操作示例
2018/06/05 Python
Python基于jieba库进行简单分词及词云功能实现方法
2018/06/16 Python
浅谈pycharm使用及设置方法
2019/09/09 Python
python关于倒排列的知识点总结
2020/10/13 Python
澳大利亚最超值的自行车之家:Reid Cycles
2019/03/24 全球购物
事业单位个人应聘自荐信
2013/09/21 职场文书
实习期自我鉴定
2013/10/11 职场文书
校园摄影活动策划方案
2014/02/05 职场文书
2014年四风个人对照检查及整改措施
2014/10/28 职场文书
2014年后勤管理工作总结
2014/12/01 职场文书
财政局个人总结
2015/03/04 职场文书
CSS 新特性 contain控制页面的重绘与重排问题
2021/04/30 HTML / CSS
Python爬虫基础之初次使用scrapy爬虫实例
2021/06/26 Python
Redis如何实现验证码发送 以及限制每日发送次数
2022/04/18 Redis
如何Tomcat中使用ipv6地址
2022/05/06 Servers