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 相关文章推荐
优化 JavaScript 代码的方法小结
Jul 16 Javascript
ExtJs默认的字体大小改变的几种方法(自己整理)
Apr 18 Javascript
js如何获取file控件的完整路径具体实现代码
May 15 Javascript
web 屏蔽BackSpace键实例代码
Dec 24 Javascript
TableSort.js表格排序插件使用方法详解
Feb 10 Javascript
微信小程序登录态控制深入分析
Apr 12 Javascript
静态页面实现 include 引入公用代码的示例
Sep 25 Javascript
解决vue-cli + webpack 新建项目出错的问题
Mar 20 Javascript
JavaScript如何对图片进行黑白化
Apr 10 Javascript
ExtJs使用自定义插件动态保存表头配置(隐藏或显示)
Sep 25 Javascript
vue登录注册实例详解
Sep 14 Javascript
layui数据表格重载实现往后台传参
Nov 15 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
星际中的相关伤害
2020/03/04 星际争霸
打造超酷的PHP数据饼图效果实现代码
2011/11/23 PHP
初识通用数据库操作类――前端easyui-datagrid,form(php)
2015/07/31 PHP
PHP学习笔记之php文件操作
2016/06/03 PHP
在jquery中处理带有命名空间的XML数据
2011/06/13 Javascript
JavaScript中的Primitive对象封装介绍
2014/12/31 Javascript
jQuery基本过滤选择器用法示例
2016/09/09 Javascript
JS简单去除数组中重复项的方法
2016/09/13 Javascript
浅谈JQ中mouseover和mouseenter的区别
2016/09/13 Javascript
使用node.js搭建服务器
2017/05/20 Javascript
JavaScript数据结构之优先队列与循环队列实例详解
2017/10/27 Javascript
Angular实现可删除并计算总金额的购物车功能示例
2017/12/26 Javascript
JS 正则表达式验证密码、邮箱格式的实例代码
2018/10/28 Javascript
实现一个 Vue 吸顶锚点组件方法
2019/07/10 Javascript
react实现移动端下拉菜单的示例代码
2020/01/16 Javascript
[01:52]DOTA2完美大师赛Vega战队趣味视频——kpii老师小课堂
2017/11/25 DOTA
python基础教程之元组操作使用详解
2014/03/25 Python
Python爬虫爬验证码实现功能详解
2016/04/14 Python
Python中字符串的修改及传参详解
2016/11/30 Python
Python基于回溯法子集树模板解决全排列问题示例
2017/09/07 Python
Python符号计算之实现函数极限的方法
2019/07/15 Python
Python学习笔记之函数的定义和作用域实例详解
2019/08/13 Python
python3常用的数据清洗方法(小结)
2019/10/31 Python
详解Python中pyautogui库的最全使用方法
2020/04/01 Python
Python如何实现的二分查找算法
2020/05/27 Python
Python实现验证码识别
2020/06/15 Python
关于python3.7安装matplotlib始终无法成功的问题的解决
2020/07/28 Python
Ralph Lauren法国官网:美国高品味时装品牌
2017/12/08 全球购物
Holiday Inn中国官网:IHG旗下假日酒店预订
2018/04/08 全球购物
日本高岛屋百货购物网站:TAKASHIMAYA
2019/03/24 全球购物
慈善晚会策划方案
2014/05/14 职场文书
护士优质服务演讲稿
2014/08/26 职场文书
个人承诺书格式范文
2015/04/29 职场文书
原告代理词范文
2015/05/25 职场文书
妇联2016年六一国际儿童节活动总结
2016/04/06 职场文书
MySQL索引知识的一些小妙招总结
2021/05/10 MySQL