写个鼠标移动动画库,提升下PC网站体验吧

226 阅读2分钟

我正在参加「创意开发 投稿大赛」详情请看:掘金创意开发大赛来了!

前言

大家好,最近写了个前端的轻量插件库mouse-shake,实现了基于鼠标移动的动画效果。效果图如下,原理比较简单,欢迎大家体验~netlify体验地址

效果图

原理解析

1. 监听元素鼠标事件

首先确定容器,然后对容器添加鼠标事件监听,主要用到了mousemovemouseleave事件。然后再mousemove事件回调函数中计算中心点坐标、计算鼠标位置坐标、计算坐标偏移量并渲染效果即可。

  handleMouseMove (event) {
    window.requestAnimationFrame(() => {
      let position = this.getPosition(event)
      let deltaPosition = this.calcDeltaPostion(position, this.centerPosition)
      let offsetPercent = this.calOffsetPercent(position, this.centerPosition)
      this.elObjs.forEach(item => {
        this.effect(item, offsetPercent, deltaPosition)
      })
    })
  }

2. 计算中心点坐标

mouse-shake的默认容器为body元素,一般是需要实现动画的元素的父级元素即可。然后计算容器的中心点坐标。我们通过offsetwidthoffsetHeight来获取盒模型的宽与高,然后除以2即可。

mouse-shake原理相关 - 中心点.png
  getCenterPostion (obj) {
    return {
      x: obj.offsetWidth / 2,
      y: obj.offsetHeight / 2
    }
  }

3. 计算鼠标位置坐标

这里,我们要获取的是鼠标相对于容器的坐标。这边,我们不直接计算这个距离,而是通过鼠标到浏览器可见区域边缘的距离和容器到浏览器可见区域边缘的距离只差来获取,使用clientXclientYgetBoundingClientRect来实现

mouse-shake原理相关 - 光标位置.png
  getPosition (event) {
    this.containerObjRect = this.containerObj.getBoundingClientRect()
    let e = event || window.event
    return {
      x: e.clientX - this.containerObjRect.left,
      y: e.clientY - this.containerObjRect.top
    }
  }

4. 计算坐标偏移量并渲染效果

拿到了中心点坐标和鼠标位置坐标后,坐标偏移量就比较简单了,直接相减即可。另外,还可以计算下坐标偏移的百分比。

  calcDeltaPostion (postion, centerPosition) {
    return {
      x: postion.x - centerPosition.x,
      y: postion.y - centerPosition.y
    }
  }

  calOffsetPercent (postion, centerPosition) {
    return {
      xPercent: (postion.x - centerPosition.x) / centerPosition.x,
      yPercent: (postion.y - centerPosition.y) / centerPosition.y
    }
  }

然后就是效果渲染,我使用的是css的transform,对元素进行位置、角度、大小的转换。根据坐标偏移量和坐标偏移百分比计算元素偏转角度与位置改变幅度即可。

  effect (obj, offsetPercent, deltaPosition) {
    let rotateXDeg = (offsetPercent.yPercent * this.options.effectConfig.maxAngle * -1 * this.options.direction).toFixed(4)
    let rotateYDeg = (offsetPercent.xPercent * this.options.effectConfig.maxAngle * this.options.direction).toFixed(4)
    let translateXPx = (offsetPercent.xPercent * this.options.effectConfig.moveSpeed * this.options.direction).toFixed(4)
    let translateYPx = (offsetPercent.yPercent * this.options.effectConfig.moveSpeed * this.options.direction).toFixed(4)
    if (this.options.effect === 1) {
      obj.style.transform = `translateX(${translateXPx}px) translateY(${translateYPx}px)`
    } else if (this.options.effect === 2) {
      obj.style.transform = `rotateX(${rotateXDeg}deg) rotateY(${rotateYDeg}deg)`
    } else if (this.options.effect === 3) {
      obj.style.transform = `translateX(${translateXPx}px) translateY(${translateYPx}px) rotateX(${rotateXDeg}deg) rotateY(${rotateYDeg}deg)`
    }
  }

效果展示

总结

  • 优点
    1. 极小的,压缩后大约4kb
    2. 零依赖,不依赖第三方库
    3. 易使用,安装、引入加载后,一行代码即可
  • 缺点
    1. 效果单一
    2. 元素transform属性会被覆盖
    3. 移动端不适用

如有错误,请赐教。目前mouse-shake库已发布到npm,欢迎提出意见~ github地址,欢迎star。另外,目前还不够完善,体验即可,生产环境慎用。