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 相关文章推荐
excel操作之Add Data to a Spreadsheet Cell
Jun 12 Javascript
Ext 表单布局实例代码
Apr 30 Javascript
JavaScript中统计Textarea字数并提示还能输入的字符
Jun 10 Javascript
谈谈我对JavaScript DOM事件的理解
Dec 18 Javascript
基于jQuery日历插件制作日历
Mar 11 Javascript
JS+Canvas 实现下雨下雪效果
May 18 Javascript
基于Bootstrap的Metronic框架实现页面链接收藏夹功能
Aug 29 Javascript
jQuery Validate 数组 全部验证问题
Jan 12 Javascript
JS实现针对给定时间的倒计时功能示例
Apr 11 Javascript
Vue.js学习教程之列表渲染详解
May 17 Javascript
Node.js创建HTTP文件服务器的使用示例
May 11 Javascript
创建Vue项目以及引入Iview的方法示例
Dec 03 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
解析如何去掉CodeIgniter URL中的index.php
2013/06/25 PHP
PHP面向对象详解(三)
2015/12/07 PHP
php获取指定数量随机字符串的方法
2017/02/06 PHP
javascript优先加载笔记代码
2008/09/30 Javascript
JavaScript 学习点滴记录
2009/04/24 Javascript
jQuery数组处理方法汇总
2011/06/20 Javascript
javascript数组操作(创建、元素删除、数组的拷贝)
2014/04/07 Javascript
javascript类型转换示例
2014/04/29 Javascript
javascript中2个感叹号的用法实例详解
2014/09/04 Javascript
javascript对象的相关操作小结
2016/05/16 Javascript
JavaScript实现解析INI文件内容的方法
2016/11/17 Javascript
iview给radio按钮组件加点击事件的实例
2017/09/30 Javascript
angularjs实现柱状图动态加载的示例
2017/12/11 Javascript
理解 JavaScript EventEmitter
2018/03/29 Javascript
Vue.js构建你的第一个包并在NPM上发布的方法步骤
2019/05/01 Javascript
vue实现分环境打包步骤(给不同的环境配置相对应的打包命令)
2019/06/04 Javascript
vue之组件内监控$store中定义变量的变化详解
2019/11/08 Javascript
使用webpack搭建pixi.js开发环境
2020/02/12 Javascript
vue实现户籍管理系统
2020/05/29 Javascript
[01:28:43]2014 DOTA2华西杯精英邀请赛5 24 DK VS CIS
2014/05/25 DOTA
python显示天气预报
2014/03/02 Python
Python 正则表达式(转义问题)
2014/12/15 Python
Python中Threading用法详解
2017/12/27 Python
利用Python如何将数据写到CSV文件中
2018/06/05 Python
利用python脚本如何简化jar操作命令
2019/02/24 Python
详解Python的数据库操作(pymysql)
2019/04/04 Python
基于python3监控服务器状态进行邮件报警
2019/10/19 Python
浅谈Python中os模块及shutil模块的常规操作
2020/04/03 Python
Python中qutip用法示例详解
2020/10/02 Python
英国性感内衣和睡衣品牌:Bluebella
2018/01/26 全球购物
后勤副校长自我鉴定
2013/10/13 职场文书
医药营销个人求职信
2014/04/12 职场文书
教师党员个人整改措施材料
2014/09/16 职场文书
《包身工》教学反思
2016/02/23 职场文书
SpringBoot连接MySQL获取数据写后端接口的操作方法
2021/11/02 MySQL
Python 一键获取电脑浏览器的账号密码
2022/05/11 Python