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实现网页顶部固定导航效果代码
Dec 24 Javascript
jQuery实现下拉框左右移动(全部移动,已选移动)
Apr 15 Javascript
老生常谈Javascript中的原型和this指针
Oct 09 Javascript
原生JS实现匀速图片轮播动画
Oct 18 Javascript
可输入文字查找ajax下拉框控件 ComBox的实现方法
Oct 25 Javascript
Vue上传组件vue Simple Uploader的用法示例
Aug 25 Javascript
在小程序中使用腾讯视频插件播放教程视频的方法
Jul 10 Javascript
JavaScript多态与封装实例分析
Jul 27 Javascript
layer.open 按钮的点击事件关闭方法
Aug 17 Javascript
angular ng-model 无法获取值的处理方法
Oct 02 Javascript
JavaScript实现背景自动切换小案例
Sep 27 Javascript
JavaScript实现简单的图片切换功能(实例代码)
Apr 10 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/08 日漫
php中的时间显示
2007/01/18 PHP
利用static实现表格的颜色隔行显示的代码
2007/09/02 PHP
PHP操作MongoDB时的整数问题及对策说明
2011/05/02 PHP
PHP下通过exec获得计算机的唯一标识[CPU,网卡 MAC地址]
2011/06/09 PHP
php懒人函数 自动添加数据
2011/06/28 PHP
ThinkPHP中的三大自动简介
2014/08/22 PHP
利用PHP自动生成印有用户信息的名片
2016/08/01 PHP
扩展String功能方法
2006/09/22 Javascript
javascript 窗口加载蒙板 内嵌网页内容
2010/11/19 Javascript
jquery 操作两个select实现值之间的互相传递
2014/03/07 Javascript
JS实现5秒钟自动封锁div层的方法
2015/02/20 Javascript
Javascript中的Prototype到底是什么
2016/02/16 Javascript
bootstrap fileinput完整实例分享
2016/11/08 Javascript
BootStrapTable 单选及取值的实现方法
2017/01/10 Javascript
JavaScript实现简单的文本逐字打印效果示例
2018/04/12 Javascript
vue实现键盘输入支付密码功能
2018/08/18 Javascript
angular2 组件之间通过service互相传递的实例
2018/09/30 Javascript
webpack + vue 打包生成公共配置文件(域名) 方便动态修改
2019/08/29 Javascript
vue项目中在可编辑div光标位置插入内容的实现代码
2020/01/07 Javascript
JavaScript实现简单验证码
2020/08/24 Javascript
js实现删除json中指定的元素
2020/09/22 Javascript
用Python编写简单的微博爬虫
2016/03/04 Python
Python+Wordpress制作小说站
2017/04/14 Python
谈一谈基于python的面向对象编程基础
2019/05/21 Python
解决django后台样式丢失,css资源加载失败的问题
2019/06/11 Python
英国著名的药妆网站:Escentual
2016/07/29 全球购物
上班早退检讨书
2014/01/09 职场文书
机电专业大学生职业规划书范文
2014/02/25 职场文书
2014年乡镇人大工作总结
2014/11/25 职场文书
2014年科技工作总结
2014/11/26 职场文书
从严治党主题教育活动总结
2015/05/07 职场文书
食品安全责任书范本
2015/05/09 职场文书
煤矿隐患排查制度
2015/08/05 职场文书
阿里云服务器部署mongodb的详细过程
2021/09/04 MongoDB
你真的会用Mysql的explain吗
2022/03/31 MySQL