English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

JavaScript Implementation of Mouse Hover Effect Similar to Lagou.com

First, let's see the effect diagram (gif recorded by myself, a bit ugly, sorry, tool licecap)

 

Implementation idea

 HTML structure

  <ul>
    <li>
      <div class="bg">
        <p>JS</p>
      </div>
    </li>
    .....
  </ul>

    Li as the carrier for mouse entering (mouseenter) and mouse leaving (mouseleave).

    Div as the carrier for animation execution.

CSS

    Div uses absolute positioning, and its position is changed through top and left.

    Since the top and left of div may exceed the size of li, it is necessary to set li's overflow: hidden;

JS

    1、Using JS to manipulate CSS3 transition animation

    2、How to judge the direction of mouse entering and leaving

Knowledge about mouse coordinates

MouseEvent object

The following introduces some knowledge about coordinates in MouseEvent:

    (clientX, clientY): Coordinates relative to the visible area.

    (pageX, pageY): Coordinates relative to the entire page (including the area scrolled out by the scroll bar).

    (screenX, screenY): Coordinates relative to your computer screen.

    Obtain the coordinates within an element

  function pointTo(element, e) {
    var elementBox = element.getBoundingClientRect();
    return {
      x: e.clientX - elementBox.left,
      y: e.clientY - elementBox.top
    };
  }

    Calculate the coordinates of the top left corner of the element

  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
    }
  }

    Get the width and height of the element (do not consider it as width and height, beginners are especially prone to making mistakes)

  offsetHeight and offsetWidth

Simple encapsulation of CSS3 transition animation

/* options parameters: obj: the object moving speed: the duration of the movement (optional) changeStyle: the properties to be changed, here may be multiple, so the function method is used (optional) callback: callback function (optional) */
  function animation(options){
    if(!options.obj) {
      return false;
    }
    //Set default duration
    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(){
      //This is mainly due to the fact that transitionend will be executed multiple times after each property animation is completed, so we need to make sure it only executes once.
      if(!flag) {
        options.callback && options.callback();
      }
    },false);
  }

How to determine the direction

This requires the concept of tangent in mathematics, and I drew a picture, I don't know if you can understand it clearly: (very ugly...)

 

Determine the movement direction of the element

  function getDirection(element,startPoint,pagePoint){
    var halfWidth = element.offsetWidth / 2,halfHeight = element.offsetHeight / 2;
    //Obtain the center point
    var center = {
      x: startPoint.x + halfWidth,
      y: startPoint.y + halfHeight
    }
    //Obtain the distance from the mouse to the center point
    var disX = pagePoint.x - center.x;
    var disY = pagePoint.y - center.y;
    if(disY < 0 && Math.abs(disY / disX) >= 1) {
      //Above
      return 1;
    }
    else if(disY > 0 && Math.abs(disY / disX) >= 1) {
      //Down
      return 2;
    }
    else if(disX < 0 && Math.abs(disY / disX) < 1) {
      //Left
      return 3;
    }
    else {
      //Right
      return 4;
    }
  }

Code to start the event, with comments

/* Parameters in options: Triggering element: targetElement, Animation carrier: 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() {
    //Save the reference of 'this'
    var _this = this;
    _this.targetElement.addEventListener('mouseenter',function(e){
      //Obtain the mouse coordinates
      var point = {
        x: e.pageX,
        y: e.pageY
      }
      console.log(point);
      //Obtain the direction
      var dir = getDirection(_this.targetElement,startPoint(_this.targetElement),point);
      clearTimeout(_this.timeId);
      //Cancel the transition animation (to prevent triggering the transition effect when resetting the position of the animation carrier)
      _this.animationElement.style.transition = "";
      //Determine the starting position of the animation carrier by obtaining the direction of motion
      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;
      }
      //Asynchronous Execution
      _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);
  }

Summary

That's all for this article. I hope the content of this article can be helpful to everyone's learning or work. If you have any questions, you can leave a message for communication.

You May Also Like