iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 11
1
Modern Web

網頁阿尼尛,到底是在幹尛?系列 第 11

第十章、☞ 轟隆隆隆衝衝衝 Animation 引擎發動 ━☆゚.*・。 (合)

簡介

登登登 等登愣 等登愣!(傾斜45度的超長電影簡介緩緩從底部滑出)

嗨 大家好~ 今天又回到了我們 Animation 介紹的部分,並且帶大家體驗一下宇宙原力的存在,做完以後在座各位都會是絕地大師啦!

以下內容涉及 JavaScript 部分,若有興趣,歡迎去查詢跟 JavaScript 有關的動畫事件喔~

那麼我們開始吧!

動畫事件(Animation Events)

在網頁渲染動畫時,每一次的動畫生、結束與每一次的迭代結束,對會產生一個 DOM 事件。

事件發生,瀏覽器追蹤已發生但尚未處理的事件


瀏覽器呼叫相關事件

一個元素可以同時具有多個被動畫化的屬性。這發生在具有包含多個屬性的 keyframes 或是 包含多個 anoamtion-name ,就事件而言,每一個 animation-name 都會指定對應到一個動畫。因此,事件操作即是對於每一個 anomation-name 產生動畫,而不是針對每一個屬性生成事件。

當你定義了有效的 keyframes 時,每一個動畫都將運行並且產生事件,這其中包括了將 keyframes 規則設為空值的動畫

動畫的運作的時間和生成的事件一起發送。這讓是將處理程序能夠確認循環動畫時動畫當下的迭代及交替動畫的位置。此時間不包括動畫處於 暫停 的狀態。

舉例來說:

  • 下面範例取得了正在運作的動畫,並且監聽 animationend 事件。
const animated = document.querySelector('.animated');

animated.addEventListener('animationend', () => {
  console.log('Animation ended');
});
  • 下面範例一樣為取得動畫並且監聽事件,不過這個範例是透過 onanimationend 來處理動畫事件。
const animated = document.querySelector('.animated');

animated.onanimationend = () => {
  console.log('Animation ended');
};

實際應用:

// 獲取動畫元素
const animation = document.querySelector('p.animation');
const animationEventLog = document.querySelector('.animation-example>.event-log');
const applyAnimation = document.querySelector('.animation-example>button.activate');
let iterationCount = 0;

//監聽動畫觸發事件,並且將結果印在 event-log 區域內
animation.addEventListener('animationstart', () => {
  animationEventLog.textContent = `${animationEventLog.textContent}'animation started' `;
});

//監聽動畫每次迭代事件,並且將結果印在 event-log 區域內
animation.addEventListener('animationiteration', () => {
  iterationCount++;
  animationEventLog.textContent = `${animationEventLog.textContent}'animation iterations: ${iterationCount}' `;
});

//監聽動畫結束事件,並且將結果印在 event-log 區域內
animation.addEventListener('animationend', () => {
  animationEventLog.textContent = `${animationEventLog.textContent}'animation ended'`;
  animation.classList.remove('active');
  applyAnimation.textContent = "Activate animation";
});

//監聽動畫刪除事件(此事件並非所有瀏覽器都能達成),並且將結果印在 event-log 區域內
animation.addEventListener('animationcancel', () => {
  animationEventLog.textContent = `${animationEventLog.textContent}'animation canceled'`;
});

//applyAnimation 註冊 ckick 事件
applyAnimation.addEventListener('click', () => {
  // click 事件在元素上掛上 class = 'active',或移除 class = 'active'
  animation.classList.toggle('active');
  //將監聽事件結果傳進一個空字串內
  animationEventLog.textContent = '';
  // 迭代次數
  iterationCount = 0;
  let active = animation.classList.contains('active');
  //判斷元素上有無 class = 'active',若有就在 button 上顯示 'Cancel animation'
  if (active) {
    applyAnimation.textContent = "Cancel animation";
    //判斷元素上有無 class = 'active',若無就在 button 上顯示 'Activate animation'
  } else {
    applyAnimation.textContent = "Activate animation";
  }
});

AnimationEvent 屬性

動畫運作時可能發生的不同類型事件

animationstart

該事件發生在動畫發生時。如果有 動畫延遲,則會等到動畫延遲時間結束後才觸發事件。

動畫延遲將導致事件以 elapsedTime(動畫運行時間) 等於 animation-iteration-count 的絕對值方式觸發。即,在此情況下 animation-play-state 屬性無論設置 running 還是 paused,事件都將會被觸發。

  • 事件冒泡:yes
  • 是否可以取消事件:yes
  • Context Info: animationName, elapsedTime, pseudoElement

animationend

該事件發生在動畫結束時,在此情況下 elapsedTime(動畫運行時間) 值會等於動畫時間。

  • 事件冒泡:yes
  • 是否可以取消事件:no
  • Context Info: animationName, elapsedTime, pseudoElement

animationiteration

該事件發生在每一次動畫迭代結束時,但是當 animationend 事件在同一時間觸發時將會被排除該事件。也就是說當動畫迭代次數 <= 1 時,該事件就不會發生。

在此情況下,elapsedTime(動畫運行時間) 該事件等於動畫時間的乘積。其中,若假設沒有動畫延遲,則在動畫迭代完成之後,當前的迭代 index 值為 1。

  • 事件冒泡:yes
  • 是否可以取消事件:no
  • Context Info: animationName, elapsedTime, pseudoElement

animationcancel

該事件發生在動畫停止運作的那刻,例如改變 animation-name 已刪除動畫,或該動畫元素變成 display: none

在此情況下 elapsedTime(動畫運行時間) 為動畫開始到動畫被取消以來經過的秒數。

  • 事件冒泡:yes
  • 是否可以取消事件:no
  • Context Info: animationName, elapsedTime, pseudoElement

光劍光暈動畫

學到這邊,各位對於自己的 CSS Animation 能力還感到懷疑與不足嗎?
沒關係,跟著我一起來實作一次,並且相信原力,就能夠獲得無比的力量的!

  • 這次光劍的結構我們分成:1.外層框架 2.光劍光束 3.光劍握柄。首先我們將外層框架設定好:
<div class="container">
  <div class="lightsaber"></div>
  <div class="bar"></div>
</div>
.container {
  width: 100vw;
  height: 100vh;
  position:relative;
}
  • 把光劍光束與光劍握柄設定樣式,先將光束本體的寬高、定位都設定好:
.lightsaber {
  width: 15px;
  height: 200px;
  margin: 0 auto;
  background-color: #FFF;
  position: absolute;
  top: 10%;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 0;
}

.bar {
  width: 80px;
  height: 250px;
  background-image: url(https://i.imgur.com/2BB4MwC.png);
  background-repeat: no-repeat;
  background-size: cover;
  background-position: -10px 0;
  position: absolute;
  top: 40%;
  left: 0;
  right: 0;
  margin: 0 auto;
}
  • 利用偽元素 after 做出白色光束能量的部分:
.lightsaber:after {
  content: "";
  position: absolute;
  width: 110%;
  height: 110%;
  background-color: white;
  z-index: 200;
  border-radius: 20px;
}
  • 接著利用偽元素 before 來做會一閃一閃的光暈,讓光劍有「嗡嗡嗡......」的視覺效果。並且設定 動畫名稱、動畫時間、播放次數、播放方向:
.lightsaber:before {
  content: "";
  display: block;
  position: absolute;
  width: 110%;
  height: 110%;
  z-index: 1;
  background-color: #007f00;
  animation: glow 0.03s infinite alternate;
}
  • 設定光暈 keyframes,讓光暈向外擴散或內縮:
@keyframes glow {
  from {
    filter: blur(10px);
  }
  to {
    filter: blur(20px);
  }
}

完成

Use the force , luke !


有關於 Animation 的文章就到今天告一段落囉~ 感謝大家的閱讀。
大家有沒有在這三天的時間感受到宇宙原力的存在呢?沒有的話也不用氣餒,就如同電影主角路克一樣,經過不斷反覆練習,總有一天會成為最棒的絕地大師的。

如果大家有其他有趣的 Animation 作品,也歡迎多多分享給我呦!我會一直在英靈殿靜待各位並祝福大家的。

那麼 May the Force be with you

bye bye~


參考資料


上一篇
第九章、☞ 轟隆隆隆衝衝衝 Animation 引擎發動 ━☆゚.*・。 (反)
下一篇
第十一章、製作網頁動畫卻不用 Time function ? HaiYaa~~
系列文
網頁阿尼尛,到底是在幹尛?30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
PH
iT邦研究生 5 級 ‧ 2020-09-28 21:43:07

零到一百K only四秒鐘/images/emoticon/emoticon01.gif

CathyShen iT邦新手 4 級 ‧ 2020-09-28 22:50:22 檢舉

引擎發動 so come on! 引擎發動 so come on!

我要留言

立即登入留言