利用perspective和transform建立随鼠标倾斜的动画

前言

本文系翻译自 Animate a Container on Mouse Over Using Perspective and Transformjavascript

本文首发于我的博客:www.ferecord.com/animate-a-c…。如若转载请附上原文地址,以便更新溯源。css

我正在作的项目须要给用户展现大量的图片,常见的灯箱效果(放大缩小等)略显枯燥,我决定让图片的展现效果更有互动性更有趣:当鼠标在图片上移动时让图片随鼠标的移动而倾斜。html

效果以下:java

在 codePen 查看: https://codepen.io/MihaiIonescu/pen/MrLoweb

这个效果的完成须要同时用到 CSS 与 JavaScript,下面的小教程能帮助你快速的理解。浏览器

建议各位先简单了解下 perspectivetransform 后再阅读如下教程。 咱们将会在下面的教程中充分了解这两个属性的用法。函数

开始

首先咱们须要两个元素containerinnercontainer元素将会用到 perspective 属性。性能

<div id="container">
    <div id="inner"></div>
</div>
复制代码

出于演示的目的,咱们把这个元素做为卡片显示在屏幕中央:flex

body {
    /* Full screen width and height */
    width: 100%;
    min-height: 100vh;

    /* Centers the container in the middle of the screen */
    display: flex;
    justify-content: center;
    align-items: center;

    margin: 0;
    background-color: rgb(220, 220, 220);
}

#container {
    /* This will come into play later */
    perspective: 40px;
}

#inner {
    width: 20em;
    height: 18em;
    background-color: white;
}
复制代码

能够看到结果是一张白色的卡片显示在灰色的背景上。 须要注意的是代码里咱们让#container的 css perspective 值为 40px,这至关于告诉浏览器这个元素距离屏幕有 40px 的空间距离。等会儿咱们经过 transforms 属性的改变即可以让它以 3D 旋转的方式在这段空间里展现出先后倾斜效果。动画

使用 JavaScript

先来定义一个鼠标事件的控制器:

var container = document.getElementById('container');
var inner = document.getElementById('inner');

var onMouseEnterHandler = function(event) {
    update(event);
};
var onMouseLeaveHandler = function() {
    inner.style = "";
};
var onMouseMoveHandler = function(event) {
    if (isTimeToUpdate()) {
        update(event);
    }
};

container.onmouseenter = onMouseEnterHandler;
container.onmouseleave = onMouseLeaveHandler;
container.onmousemove = onMouseMoveHandler;
复制代码

这个控制器包括 3 个方面:

  • Handler Functions:这些函数用来处理鼠标进入、移动、离开事件。
  • Update Functionupdate()这个函数在这段代码里没有完整写出来,它的功能是根据鼠标移动的距离来改变 #inner 的倾斜度,咱们稍后完善这个函数。
  • Time to Update FunctionisTimeToUpdate()这个函数也没写出来,它的功能是控制 update() 的执行次数,只有当它的返回值为 true 时才执行update()。这是为了减小 update() 的执行次数,以提升代码的性能。

上面的代码将:

  • 在鼠标进入#container时,使#inner产生 3D 旋转。
  • 当鼠标在#container内移动时,以适当的时间间隔改变#inner的 3D 旋转的角度。
  • 当鼠标离开#container时,重置#inner的样式。

Is it Time to Update?

先来看看 isTimeToUpdate 函数的内容,它能够控制 update() 调用的频率:

var counter = 0;
var updateRate = 10;
var isTimeToUpdate = function() {
    return counter++ % updateRate === 0;
};
复制代码

counter 值是 updateRate 的整数倍时,更新才会发生。这段代码表示 isTimeToUpdate() 每执行 10 次,更新才会发生一次。

鼠标

接下来咱们建立一个对象用来记录鼠标的位置,提示一下,对于 js 的初学者来讲这段代码可能乍看之下挺复杂,但其实很容易理解。

// Init
var container = document.getElementById('container');
var inner = document.getElementById('inner');

// Mouse 
var mouse = {
    _x: 0,
    _y: 0,
    x: 0,
    y: 0,
    updatePosition: function(event) {
        var e = event || window.event;
        this.x = e.clientX - this._x;
        this.y = (e.clientY - this._y) * -1;
    },
    setOrigin: function(e) {
        this._x = e.offsetLeft + Math.floor(e.offsetWidth/2);
        this._y = e.offsetTop + Math.floor(e.offsetHeight/2);
    },
    show: function() { return '(' + this.x + ', ' + this.y + ')'; }
}

// 设置鼠标的中心位置
mouse.setOrigin(container);
复制代码

咱们来聊一聊这段代码,它主要包括这几个函数:

  • show(): 用来展现鼠标的当前位置(你能够用 console.log() 或别的什么方式)。
  • setOrigin(): 设置鼠标的初始坐标,即把#container的中心位置设为(0,0)
  • updatePosition(): 获取鼠标当前相对(0,0)的坐标位置。

代码完成后后效果如图:

在 codePen 查看: https://codepen.io/MihaiIonescu/pen/JpVPLQ

鼠标位置改变时改变样式

也就是咱们上文提到过的update()函数:

var update = function(event) {
    mouse.updatePosition(event);
        updateTransformStyle(
        (mouse.y / inner.offsetHeight/2).toFixed(2),
        (mouse.x / inner.offsetWidth/2).toFixed(2)
    );
};

var updateTransformStyle = function(x, y) {
    var style = "rotateX(" + x + "deg) rotateY(" + y + "deg)";
    inner.style.transform = style;
    inner.style.webkitTransform = style;
    inner.style.mozTransform = style;
    inner.style.msTransform = style;
    inner.style.oTransform = style;
};

复制代码
  • update():在鼠标位置改变时更新 #inner 的样式。
  • updateTransformStyle(): 更新元素样式的 transform 属性。

通过以上代码,咱们彷佛已经王城了,鼠标移动时卡片也会以相同的角度 3D 转动,但看起来不太丝滑:

知道为何吗? 由于咱们为了性能设置了 isTimeToUpdate() 每执行 10 次,更新才会发生一次!这致使了每次更新之间会发生卡顿。

在 codePen 查看:https://codepen.io/MihaiIonescu/pen/VQWWgj

如何解决?使用 CSS transitions 就可让这段动画变的丝滑。

使用 Transitions

#inner {
    transition: transform 0.5s;
}
复制代码

你能够以本身的喜爱来设置 perspective 的值和 transition 的持续时间。来看下最终结果:

在 codePen 查看: https://codepen.io/MihaiIonescu/pen/MQoodL

总结

经过这种简单的方法咱们让一个图片更有交互性,你能够把这种方法应用到表单、弹框等等任何元素上。

另外这里有个纯 css 实现相同效果的方法,同窗有兴趣能够了解一下:https://codepen.io/onediv/pen/BprVzp

相关文章
相关标签/搜索