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 相关文章推荐
CSS(js)限制页面显示的文本字符长度
Dec 27 Javascript
JS获取页面input控件中所有text控件并追加样式属性
Feb 25 Javascript
javascript中的=等号个数问题两个跟三个有什么区别
Oct 23 Javascript
Node.js下自定义错误类型详解
Oct 17 Javascript
玩转NODE.JS(四)-搭建简单的聊天室的代码
Nov 11 Javascript
jQuery 获取select选中值及清除选中状态
Dec 13 Javascript
详解vue.js2.0父组件点击触发子组件方法
May 10 Javascript
荐书|您有一份JavaScript书单待签收
Jul 21 Javascript
HTML5开发Kinect体感游戏的实例应用
Sep 18 Javascript
简单明了区分escape、encodeURI和encodeURIComponent
May 26 Javascript
vue element项目引入icon图标的方法
Jun 06 Javascript
Vue实现远程获取路由与页面刷新导致404错误的解决
Jan 31 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
支持数组的ADDSLASHES的php函数
2010/02/16 PHP
一个简单php扩展介绍与开发教程
2010/08/19 PHP
php基于str_pad实现卡号不足位数自动补0的方法
2014/11/12 PHP
js兼容火狐显示上传图片预览效果的方法
2015/05/21 Javascript
微信小程序 商城开发(ecshop )简单实例
2017/04/07 Javascript
浅谈JS中的常用选择器及属性、方法的调用
2017/07/28 Javascript
VUE2.0 ElementUI2.0表格el-table自适应高度的实现方法
2018/11/28 Javascript
jquery实现商品sku多属性选择功能(商品详情页)
2019/12/20 jQuery
python计算最小优先级队列代码分享
2013/12/18 Python
Python创建系统目录的方法
2015/03/11 Python
Python模块结构与布局操作方法实例分析
2017/07/24 Python
python爬取网页转换为PDF文件
2018/06/07 Python
对Python 语音识别框架详解
2018/12/24 Python
opencv python 图像轮廓/检测轮廓/绘制轮廓的方法
2019/07/03 Python
Python 图像处理: 生成二维高斯分布蒙版的实例
2019/07/04 Python
详解python中eval函数的作用
2019/10/22 Python
从训练好的tensorflow模型中打印训练变量实例
2020/01/20 Python
python列表的逆序遍历实现
2020/04/20 Python
Tensorflow中的降维函数tf.reduce_*使用总结
2020/04/20 Python
Python内存映射文件读写方式
2020/04/24 Python
python中字典增加和删除使用方法
2020/09/30 Python
Python使用内置函数setattr设置对象的属性值
2020/10/16 Python
企业统计员岗位职责
2013/12/13 职场文书
大学生旅游业创业计划书
2014/01/29 职场文书
全国文明单位申报材料
2014/05/31 职场文书
书法大赛策划方案
2014/06/04 职场文书
学生干部培训方案
2014/06/12 职场文书
法定授权委托证明书
2014/09/27 职场文书
2014年机关后勤工作总结
2014/12/16 职场文书
停电调休通知
2015/04/16 职场文书
2019年入党思想汇报
2019/03/25 职场文书
2019暑假学生安全口号
2019/06/27 职场文书
JavaScript实现登录窗体
2021/06/22 Javascript
Ajax实现三级联动效果
2021/10/05 Javascript
详解Alibaba Java诊断工具Arthas查看Dubbo动态代理类
2022/04/08 Java/Android
阿里云国际版 使用Nginx作为HTTPS转发代理服务器
2022/05/11 Servers