あっくんブログ Written by Akihiro Tsuji

JavaScriptでDOM操作を利用したアニメーション

JavaScript プログラミング

こんにちはあっくんです。気分が落ち込んで、やる気がなくなることありませんか?そんなときは、簡単な行動をすると、やる気が出ます。例えば散歩を10分します。友達に電話します。タイピングの練習をします(寿司打)とか。僕は、ステッパーで足踏みして、ぼーっと動画みたりします。

今回はDOM操作を利用したアニメーションを学んでいきましょー!

クラスとCSSを組み合わせた方法や、CSSを直接操作する方法があります。

クラスのつけ外しによるアニメーション

例、.classList.toggle()。オープンクラスをつけ外しすることでアニメーションを実現します。

* !importantは一言でいえば、合わせて使用したプロパティを最優先で使用することにする命令です。

Image from Gyazo
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <style> /* idがmsgの要素 */ #msg { border: solid 2px #ccc; border-radius: 0.3em; padding: 1em; } /* idがmsgBtnの要素 */ #msgBtn { border: solid 2px #ccc; border-radius: 0.3em; text-align: center; padding: 0.3em; } /* idがmsgBodyの要素 */ #msgBody { overflow: hidden; /*はみ出した場合*/ height: 30px; /*高さ*/ opacity: 0.2; /*透明度*/ transition: 0.8s; /*アニメーション時間0.8秒*/ } .open { overflow-y: scroll !important; /*はみ出した場合*/ height: 200px !important; /*高さ*/ opacity: 1 i !important; /*透明度*/ } </style> </head> <body> <div id="msg"> <div id="msgBody"></div> <div id="msgBtn">続きを読む</div> </div> <script> // ダミーテキストを作成して、idがmsgBodyの要素に設定 const tDummy = "coffee cake".repeat(1000); document.querySelector("#msgBody").innerText = tDummy; // idがmenuの要素に、クリック時の処理を登録 document.querySelector("#msgBtn").addEventListener("click", (e) => { // クラスがmenuBarの要素に処理 document.querySelector("#msgBody").classList.toggle("open"); }); </script> </body> </html>
Code language: HTML, XML (xml)

CSSの値変更によるアニメーション

一定時間ごとに画面を書き換えて、少しずつ描画内容をかえれば、アニメーションは実現できます。

構文

変数= 関数(現在時刻のタイムスタンプのタイムスタンプ{ //アニメーションの処理 requestAnimationFrame(変数//2回目以降の実行 } requestAnimationFrame(変数//初回の実行
Code language: JavaScript (javascript)

アニメーション用のメソッド

requestAnimationFrame(f)
Webブラウザの描画タイミングで関数fを実行する。requestIDを返します。

canselAnimationFrame(id)
requestIDに対するアニメーションをキャンセルします。

例、requestAnimationFrame()。要素のスタイルを書き換えて、アニメーション処理をする例を示します。Webページの背後に泡が出て、上に移動していくアニメーションです。

* document.createTextNode()で文字列のノードを作れます。

* document.bodyでbody要素を直接操作できます。

* Math.random()は0以上1未満のランダムな浮動小数点を返します。

* parseFloat()は現在の位置を数値化します。

Image from Gyazo
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <style> /* 泡用のスタイル */ .bubble { position: fixed; /*固定位置*/ z-index: -99; /*文字などの要素の後ろに*/ width: 100px; /*横幅*/ height: 100px; /*高さ*/ border-radius: 50px; /*半径*/ background: #48d; /*背景色*/ opacity: 0.2; /*透明度*/ } </style> </head> <body> <script> // ダミーテキストを作成してして、bodyに設定 const tDummy = "coffee cake".repeat(1000); const elDummy = document.createTextNode(tDummy); document.body.appendChild(elDummy); // 泡を作成して,bodyに設定 const size = 30; //泡要素の数 const elArr = []; //泡要素の配列 for (let i = 0; i < size; i++) { // x,y座標を作成 const x = Math.random() * window.innerWidth - 50; const y = Math.random() * window.innerHeight - 50; // div要素を作成して、 スタイルで位置を設定 elArr[i] = document.createElement("div"); elArr[i].classList.add("bubble"); elArr[i].style.left = `${x}px`; elArr[i].style.top = `${y}px`; // bodyに追加 document.body.appendChild(elArr[i]); } // タイムスタンプ記録用変数 let tmOld = 0; // アニメーション用関数 const step = function(tm) { // タイムスタンプの差分を求めて、過去値を更新 let tmDif = tm - tmOld; if (tmDif > 1000) { tmDif = 0; } tmOld = tm; // コンソールに出力 console.log(`time : ${tm}, tmDif : ${tmDif}`); // すべての要素に処理 elArr.forEach((el) => { // 現在の位置 const xEl = parseFloat(el.style.left); const yEl = parseFloat(el.style.top); // タイムスタンプの時間から移動を計算 let x = xEl; let y = yEl - tmDif / 80; // 画面の上から出たら、画面のしたに移動 if (y < -100) { y = window.innerHeight; } // 位置の反映 el.style.left = `${x}px`; el.style.top = `${y}px`; }); // アニメーションの再実行 requestAnimationFrame(step); }; // アニメーションの実行 requestAnimationFrame(step); </script> </body> </html>
Code language: HTML, XML (xml)

animate()によるアニメーション

要素にアニメーションの処理を指定します。

要素にアニメーションの処理を指定するメソッド

.animate(a, b)
変化させるスタイル設定aと、変化の時間などの設定bを指定して、要素をアニメーションさせます。Animationオブジェクトを返します。実行の順番にスタイルは変化していきます。

構文

.animate([ {スタイル名: 値, スタイル名: 値, スタイル名: 値 }, {スタイル名: 値, スタイル名: 値, スタイル名: 値 }, {スタイル名: 値, スタイル名: 値, スタイル名: 値 }, ], b)

構文

.animate([ スタイル名: [値, 値, 値], スタイル名: [値, 値, 値], スタイル名: [値, 値, 値] ], b)

アニメーションのプロパティ

delay
アニメーションの開始を遅らせるミリ秒。

duration
アニメーションを行なうミリ秒。

easing
エフェクト動き方。

endDelay
アニメーション終了後、次の処理に移行するミリ秒。

変化の詳細設定のeasingの値

ease
開始と完了を滑らかに。

liner
一定。

ease-in
ゆっくり開始。

ease-out
ゆっくり完了。

ease-in-out
ゆっくり開始、ゆっくり完了。

Animationオブジェクトのプロパティ

.currentTime
アニメーションの現在時間ミリ秒。

.finished
アニメーションの終了時に処理をおこなうPromise。

.onfinish
finishイベントの関数の設定をおこないます。

Animationオブジェクトのメソッド

.play()
アニメーションを再生もしくは再開。

.pause()
再生を一時を停止。

.reverse()
アニメーションを逆再生。

.finish()
再生を終了。

.cancel()
全てのキーフレームを消去し、再生中断。

例、ボックスが丸になりながら回転したあと、色が変化しながら、ぴょこんと跳ねるアニメーションを繰り返す。

* async functionにすることで、Promiseによる非同期処理を、awaitでまちながら進めます。

* .finishedプロパティを使い、Promiseoiu非同期処理のオブジェクトを得ます。

Image from Gyazo
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <style> /* アニメーション用の領域 */ .animArea { position: relative; /*位置は相対位置*/ width: 100px; /*横幅*/ height: 400px; /*高さ*/ margin: 50px auto; /*上下のマージンは50px,左右は自動*/ background: #eee; } /* アニメーションするボックス */ .box { position: absolute; /*位置は親に対する絶対位置*/ width: 100px; /*横幅*/ height: 100px; /*高さ*/ top: 300px; /*上位置*/ background: #fae; /*背景色*/ } </style> </head> <body> <div class="animArea"> <div class="box"></div> </div> <script> // classがboxの要素を選択 const elBox = document.querySelector(".box"); // アニメーション関数 anim(elBox); // アニメーション関数 async function anim(el) { // 四角→ 丸、 回転→ 四角」 アニメーション await el.animate({ borderRadius: ["0px", "50px", "0px"], transform: ["", "rotate(720deg)", ""], }, 1500 ).finished; //1500ミリ秒かけて変化 //Promiseを得る // 「下,赤→上,青→下,赤」のアニメーション await el.animate( [{ top: "300px", background: "#faa", }, { top: "0px", background: "#aaf", }, { top: "300px", background: "#faa", }, ], { delay: 250, //250ミリ秒送らせて開始 duration: 750, //750ミリ秒かけて変化 easing: "ease-in-out", //変化の種類はease-in-out endDelay: 250, //250ミリ秒送らせて終了 } ).finished; //Promiseを得る anim(el); //アニメーションの再実行 } </script> </body> </html>
Code language: HTML, XML (xml)

読んでいただいてありがとうございました。JavaScript完全入門で、勉強させていただいてます。