こんにちは。KOUKIです。
本記事は、Udemyの「50 Projects In 50 Days – HTML, CSS & JavaScript」で学習したことを載せています。
<目次>
実装するもの
今回は、「いいね機能」をJavaScriptで実装したいと思います。
demoは「こちら」で確認できます。
環境構築
簡単な環境構築をお願いします。
必要なファイルは、以下の通りです。
1 2 3 4 5 6 |
$ tree . ├── index.html ├── script.js └── style.css |
CSS版
ページ(HTML)の作成
最初にページを作成しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog==" crossorigin="anonymous" /> <link rel="stylesheet" href="style.css" /> <title>Double Click Heart</title> </head> <body> <h3>Double click on the image to <i class="fas fa-heart"></i> it</h3> <small>You liked it <span id="times">0</span> times</small> <div class="loveMe"></div> <script src="script.js"></script> </body> </html> |
このHTMLをブラウザ上で表示すると以下のようになります。

スタイル(CSS)を装飾
次にスタイルを記述しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
@import url('https://fonts.googleapis.com/css?family=Oswald'); * { box-sizing: border-box; } body { font-family: 'Oswald', sans-serif; text-align: center; overflow: hidden; margin: 0; } h3 { margin-bottom: 0; text-align: center; } small { display: block; margin-bottom: 20px; text-align: center; } .fa-heart { color: red; } .loveMe { height: 440px; width: 300px; background: url('https://images.unsplash.com/photo-1504215680853-026ed2a45def?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=334&q=80') no-repeat center center/cover; margin: auto; cursor: pointer; max-width: 100%; position: relative; box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); } .loveMe .fa-heart { position: absolute; animation: grow 0.6s linear; transform: translate(-50%, -50%) scale(0); } @keyframes grow { to { transform: translate(-50%, -50%) scale(10); opacity: 0; } } |
ここまで実装すると以下のようになります。

画像は、imgixから取得しています。
JavaScriptの実装
要素の取得
画面操作に必要な要素を取得します。
1 2 3 |
// 要素の取得 const loveMe = document.querySelector('.loveMe') const times = document.querySelector('#times') |
クリックイベントの登録
画像をクリックしたときにイベントを発火させたいので、clickイベントを登録します。
1 2 3 4 |
// クリックイベントの登録 loveMe.addEventListener('click', (e) => { }) |
クリック時間の制御
今回のいいね機能は、画像をダブルクリックした時にいいねがつきます。そのため、一定間隔で画像が押された時に処理が発火するように制御します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// クリック時間の制御 let clickTime = 0 loveMe.addEventListener('dbclick', (e) => { if(clickTime === 0) { clickTime = new Date().getTime() } else { if((new Date().getTime() - clickTime) < 800) { } else { clickTime = new Date().getTime() } } }) |
実は、ダブルクリックした時に発火するdblclickイベントというものもありますが、これは時間間隔を制御できないので、clickイベントを使っています。
ハートを作る
次に、画像をダブルクリックすると表示されるハートを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
// ハートの作成 const createHeart = (e) => { // https://fontawesome.com/ const heart = document.createElement('i') heart.classList.add('fas') heart.classList.add('fa-heart') // クリックした位置を取得 const x = e.clientX const y = e.clientY // ページからみて画像の位置を取得 const leftOffset = e.target.offsetLeft const topOffset = e.target.offsetTop // ハートを出す位置を制御 // 画像の位置とクリック位置から計算 const xInside = x - leftOffset const yInside = y - topOffset // ハートの位置を指定 // スタイルの.loveMe .fa-heart {}にてposition: absolute;を // 指定しているため、位置を制御できる heart.style.top = `${yInside}px` heart.style.left = `${xInside}px` // 子要素として追加 loveMe.appendChild(heart) } |
ハートは、Font Awesomeを使っています。
計算式を色々と書いてますが、これは丸暗記でOKだと思います。ページからみて画像の位置(offsetTop/offsetLeft)、クリックイベントからみてクリック位置(clientX/clientY)をそれぞれ取得し、減算処理を行ってハートを出す位置を算出しています。この計算式を覚えていれば、他のアプリでも応用が効くと思います。
例えば、こんな感じで外だしすれば、他のアプリでも使いまわせますね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function culcPosition(e) { // クリックした位置を取得 const x = e.clientX const y = e.clientY // ページからみて画像の位置を取得 const leftOffset = e.target.offsetLeft const topOffset = e.target.offsetTop // ハートを出す位置を制御 // 画像の位置とクリック位置から計算 const xInside = x - leftOffset const yInside = y - topOffset return {xInside, yInside} } |
計算結果は、「position: absolute」の位置として「top/left」に追加しています。
この処理は、クリックイベントから呼び出します。
1 2 3 4 5 6 7 8 9 10 11 12 |
loveMe.addEventListener('click', (e) => { if(clickTime === 0) { clickTime = new Date().getTime() } else { if((new Date().getTime() - clickTime) < 800) { createHeart(e) clickTime = 0 // 初期化 } else { clickTime = new Date().getTime() } } }) |
ハートが現れたらダブルクリックイベント完了のため、「clickTime = 0」にて、初期化をしています。
いいね数をカウント
次は、いいね数をカウントする処理を実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// クリック時間の制御 // いいね数をカウント let timesClicked = 0 // クリックイベントの登録 // ハートの作成 const createHeart = (e) => { ... // いいね数を増加して挿入 times.innerHTML = ++timesClicked } |
createHeart関数の最後に、timesClicked変数に格納した数値を挿入する処理を入れました。これでダブルクリックした時に、いいね数がカウントされるようになります。
ハート要素のクリーンアップ
最後にハート要素をクリーンアップをして、終わりにしましょう。
ハートを作り続けると、ハート要素が以下のようになります。

このハート要素はいらないので、5秒後に削除する処理をcreateHeart関数に入れましょう。
1 2 3 4 5 6 7 8 9 10 |
// ハートの作成 const createHeart = (e) => { ... // いいね数を増加して挿入 times.innerHTML = ++timesClicked // クリックするとハート要素が無限に増えていくため、5秒後に削除 setTimeout(() => heart.remove(), 5000) } |
setTimeoutは、指定した関数を指定したミリ秒後に実行してくれる便利な関数です。今回は、5000ミリ秒(5秒)を指定して、ハートを消しています。
作成したハートもremoveメソッドを使えば消せるという点は、勉強になりますね。
これで、完成です。
おわりに
いいね機能をいつか実装してみたいと思っていました!
今回の講義は、その意味で素晴らしいですね^^
JavaScriptもそうですが、CSSのアニメーションの組み合わせ方とかも非常に勉強になります!
それでは、また!
JavaScriptまとめ
JavaScript ソースコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
// 要素の取得 const loveMe = document.querySelector('.loveMe') const times = document.querySelector('#times') // クリック時間の制御 let clickTime = 0 // いいね数をカウント let timesClicked = 0 // クリックイベントの登録 loveMe.addEventListener('click', (e) => { if(clickTime === 0) { clickTime = new Date().getTime() // UNIX TIMEでデータを取得できる } else { if((new Date().getTime() - clickTime) < 800) { createHeart(e) clickTime = 0 // 初期化 } else { clickTime = new Date().getTime() } } }) // ハートの作成 const createHeart = (e) => { // https://fontawesome.com/ const heart = document.createElement('i') heart.classList.add('fas') heart.classList.add('fa-heart') const {xInside, yInside} = culcPosition(e) // ハートの位置を指定 // スタイルの.loveMe .fa-heart {}にてposition: absolute;を // 指定しているため、位置を制御できる heart.style.top = `${yInside}px` heart.style.left = `${xInside}px` // 子要素として追加 loveMe.appendChild(heart) // いいね数を増加して挿入 times.innerHTML = ++timesClicked // クリックするとハート要素が無限に増えていくため、5秒後に削除 setTimeout(() => heart.remove(), 5000) } // 要素を出す位置を計算 function culcPosition(e) { // クリックした位置を取得 const x = e.clientX const y = e.clientY // ページからみて画像の位置を取得 const leftOffset = e.target.offsetLeft const topOffset = e.target.offsetTop // ハートを出す位置を制御 // 画像の位置とクリック位置から計算 const xInside = x - leftOffset const yInside = y - topOffset return {xInside, yInside} } |
コメントを残す
コメントを投稿するにはログインしてください。