利用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

相關文章
相關標籤/搜索