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 相关文章推荐
jQuery实现复选框成对选择及对应取消的方法
Mar 03 Javascript
JavaScript函数学习总结以及相关的编程习惯指南
Nov 16 Javascript
简单的js计算器实现
Oct 26 Javascript
微信小程序授权获取用户详细信息openid的实例详解
Sep 20 Javascript
深入浅析javascript继承体系
Oct 23 Javascript
vue.js element-ui tree树形控件改iview的方法
Mar 29 Javascript
layui radio性别单选框赋值方法
Aug 15 Javascript
vue和iview实现Scroll 数据无限滚动功能
Oct 31 Javascript
webpack优化之代码分割与公共代码提取详解
Nov 22 Javascript
jquery选择器和属性对象的操作实例分析
Jan 10 jQuery
vue实现图片上传功能
May 28 Javascript
解决vue init webpack 下载依赖卡住不动的问题
Nov 09 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 正则表达式之正则处理函数小结(preg_match,preg_match_all,preg_replace,preg_split)
2012/10/05 PHP
深入php处理整数函数的详解
2013/06/09 PHP
CSS+JS构建的图片查看器
2006/07/22 Javascript
一步一步教你写一个jQuery的插件教程(Plugin)
2009/09/03 Javascript
Angularjs注入拦截器实现Loading效果
2015/12/28 Javascript
基于jQuery实现Tabs选项卡自定义插件
2016/11/21 Javascript
JS实现的tab切换选项卡效果示例
2017/02/28 Javascript
ReactNative踩坑之配置调试端口的解决方法
2017/07/28 Javascript
React Native 环境搭建的教程
2017/08/19 Javascript
利用nginx + node在阿里云部署https的步骤详解
2017/12/19 Javascript
C#程序员入门学习微信小程序的笔记
2019/03/05 Javascript
微信小程序学习笔记之文件上传、下载操作图文详解
2019/03/29 Javascript
记一次Vue.js混入mixin的使用(分权限管理页面)
2019/04/17 Javascript
Vue源码分析之Vue实例初始化详解
2019/08/25 Javascript
Vue使用富文本编辑器Vue-Quill-Editor(含图片自定义上传服务、清除复制粘贴样式等)
2020/05/15 Javascript
15个简单的JS编码标准让你的代码更整洁(小结)
2020/07/16 Javascript
浅谈vue中document.getElementById()拿到的是原值的问题
2020/07/26 Javascript
Vue 电商后台管理项目阶段性总结(推荐)
2020/08/22 Javascript
跟老齐学Python之数据类型总结
2014/09/24 Python
分享Python字符串关键点
2015/12/13 Python
python使用threading获取线程函数返回值的实现方法
2017/11/15 Python
python编程嵌套函数实例代码
2018/02/11 Python
Python 分享10个PyCharm技巧
2019/07/13 Python
django rest framework 实现用户登录认证详解
2019/07/29 Python
python实现布隆过滤器及原理解析
2019/12/08 Python
pytorch 实现tensor与numpy数组转换
2019/12/27 Python
了解一下python内建模块collections
2020/09/07 Python
Linux如何修改文件和文件夹的权限
2013/09/05 面试题
公司贷款承诺书
2014/05/30 职场文书
幼儿园爱国卫生月活动总结
2014/06/30 职场文书
环保志愿者活动方案
2014/08/14 职场文书
2014幼儿园卫生保健工作总结
2014/12/05 职场文书
法务专员岗位职责
2015/02/14 职场文书
教师辞职信范文
2015/02/28 职场文书
能让Python提速超40倍的神器Cython详解
2021/06/24 Python
小程序实现悬浮按钮的全过程记录
2021/10/16 HTML / CSS