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 相关文章推荐
阻止事件(取消浏览器对事件的默认行为并阻止其传播)
Nov 03 Javascript
不使用ajax实现无刷新提交表单
Dec 21 Javascript
JavaScript定时显示广告代码分享
Mar 02 Javascript
Javascript6中字符串的四个新用法分享
Sep 11 Javascript
js仿搜狐视频记录片列表展示效果
May 30 Javascript
three.js绘制地球、飞机与轨迹的效果示例
Feb 28 Javascript
JS实现的base64加密解密操作示例
Apr 18 Javascript
Vue中的基础过渡动画及实现原理解析
Dec 04 Javascript
微信小程序常见页面跳转操作简单示例
May 01 Javascript
深入学习JavaScript中的bom
May 27 Javascript
前端天气插件tpwidget使用方法详解
Jun 24 Javascript
详解JavaScript 事件流
Sep 02 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
WHOIS类的修改版
2006/10/09 PHP
php实现的一个很好用HTML解析器类可用于采集数据
2013/09/23 PHP
yii2.0之GridView自定义按钮和链接用法
2014/12/15 PHP
php组合排序简单实现方法
2016/10/15 PHP
php apache开启跨域模式过程详解
2019/07/08 PHP
基于Jquery的将DropDownlist的选中值赋给label的实现代码
2011/05/06 Javascript
jquerymobile checkbox及时刷新才能获取其准确值
2012/04/14 Javascript
js 自定义个性下拉选择框示例
2013/08/20 Javascript
JavaScript中的类数组对象介绍
2014/12/30 Javascript
Js+Ajax,Get和Post在使用上的区别小结
2016/06/08 Javascript
NodeJS处理Express中异步错误
2017/03/26 NodeJs
vuex state及mapState的基础用法详解
2018/04/19 Javascript
手把手教你写一个微信小程序(推荐)
2018/10/17 Javascript
layui-laydate时间日历控件使用方法详解
2018/11/15 Javascript
微信小程序实现slideUp、slideDown滑动效果及点击空白隐藏功能示例
2018/12/11 Javascript
VeeValidate 的使用场景以及配置详解
2019/01/11 Javascript
[03:44]2015国际邀请赛选手档案—Cloud9.NoTail
2015/07/28 DOTA
[07:39]第一届亚洲邀请赛回顾视频
2017/02/14 DOTA
Python中atexit模块的基本使用示例
2015/07/08 Python
Python中多个数组行合并及列合并的方法总结
2018/04/12 Python
Python中应该使用%还是format来格式化字符串
2018/09/25 Python
Django 实现购物车功能的示例代码
2018/10/08 Python
Python 普通最小二乘法(OLS)进行多项式拟合的方法
2018/12/29 Python
python pandas模块基础学习详解
2019/07/03 Python
Python生成六万个随机,唯一的8位数字和数字组成的随机字符串实例
2020/03/03 Python
python爬虫实现POST request payload形式的请求
2020/04/30 Python
Python使用configparser读取ini配置文件
2020/05/25 Python
Html5 页面适配iPhoneX(就是那么简单)
2019/09/05 HTML / CSS
UNIX文件类型
2013/08/29 面试题
Ajax实现页面无刷新留言效果
2021/03/24 Javascript
解除聘用合同证明书范本
2014/09/11 职场文书
个人学习群众路线心得体会
2014/11/05 职场文书
夫妻吵架保证书
2015/05/08 职场文书
小学作文之描写天气
2019/08/15 职场文书
Sql-Server数据库单表查询 4.3实验课
2021/04/05 SQL Server