JavaScriptでのいいね!機能
「Views」フォルダ内に「js」フォルダを作成し、その中に「like.jp」ファイルを作成します。
home.phpを以下のように修正します。
htdocs/Twitter/Views/home.php
<?php
// ツイート一覧
$view_tweets = [
[
'user_id' => 1,
'user_name' => 'ichiro.suzuki',
'user_nickname' => '鈴木一郎',
'user_image_name' => 'sample.jpg',
'tweet_body' => 'いまプログラミングをしています。',
'tweet_image_name' => null,
'tweet_created_at' => '2021-11-01 12:00:00',
'like_id' => null,
'like_count' => 0,
],
[
'user_id' => 2,
'user_name' => 'jiro.suzuki',
'user_nickname' => '鈴木二郎',
'user_image_name' => 'sample2.jpg',
'tweet_body' => '競馬場に来ました。',
'tweet_image_name' => 'sample.jpg',
'tweet_created_at' => '2021-11-02 09:00:00',
'like_id' => 1,
'like_count' => 1,
]
];
?>
<!DOCTYPE html>
<html>
<lang="ja">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<link rel="stylesheet" href="../Views/css/style.css">
<!-- ★変更箇所1(ここから)-->
<script src="https://code.jquery.com/jquery-3.6.0.js" integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk=" crossorigin="anonymous"></script>
<script src="../Views/js/like.js"></script>
<!-- ★変更箇所1(ここまで)-->
<title>Twitter</title>
</head>
<body class="home">
<div class="container">
<div class="side">
<div class="side-inner">
<ul class="nav flex-column">
<li class="nav-item"><a href="home.php" class="nav-link"><img src="../Views/img/1.svg" alt="" class="icon"></a></li>
<li class="nav-item"><a href="home.php" class="nav-link"><img src="../Views/img/2.svg" alt=""></a></li>
<li class="nav-item"><a href="search.php" class="nav-link"><img src="../Views/img/3.svg" alt=""></a></li>
<li class="nav-item"><a href="notification.php" class="nav-link"><img src="../Views/img/4.svg" alt=""></a></li>
<li class="nav-item"><a href="profile.php" class="nav-link"><img src="../Views/img/5.svg" alt=""></a></li>
<li class="nav-item"><a href="post.php" class="nav-link"><img src="../Views/img/6.svg" alt="" class="icon"></a></li>
<li class="nav-item"><img src="../Views/img_uploaded/user/sample.jpg" alt="" class="my-icon"></li>
</ul>
</div>
</div>
<div class="main">
<div class="main-header">
<h1>ホーム</h1>
</div>
<!-- ツイート投稿エリア -->
<div class="tweet-post">
<div class="my-icon">
<img src="../Views/img_uploaded/user/sample.jpg" alt="">
</div>
<div class="input-area">
<form action="post.php" method="post" enctype="multipart/form-data">
<textarea name="body" placeholder="Hello" maxlength="140"></textarea>
<div class="bottom-area">
<div class="mb-0">
<input type="file" name="image" class="form-control form-control-sm">
</div>
<button class="btn" type="submit">つぶやく</button>
</div>
</form>
</div>
</div>
<!-- 仕切りエリア -->
<div class="ditch"></div>
<!-- ツイート一覧エリア -->
<?php if (empty($view_tweets)): ?>
<p class="p-3">ツイートがありません</p>
<?php else: ?>
<div class="tweet-list">
<?php foreach ($view_tweets as $view_tweet) : ?>
<div class="tweet">
<div class="user">
<a href="profile.php?user_id=<?php echo $view_tweet['user_id']; ?>">
<img src="img_uploaded/user/<?php echo $view_tweet['user_image_name']; ?>" alt="">
</a>
</div>
<div class="content">
<div class="name">
<a href="profile.php?user_id=<?php echo $view_tweet['user_id']; ?>">
<span class="nickname"><?php echo $view_tweet['user_nickname']; ?></span>
<span class="user-name">@<?php echo $view_tweet['user_name']; ?> ・<?php echo $view_tweet['tweet_created_at']; ?></span>
</a>
</div>
<p><?php echo $view_tweet['tweet_body'] ?></p>
<?php if (isset($view_tweet['tweet_image_name'])) : ?>
<img src="img_uploaded/tweet/<?php echo $view_tweet['tweet_image_name']; ?>" alt="" class="post-image">
<?php endif; ?>
<div class="icon-list">
<!-- ★変更箇所2(ここから)-->
<div class="like js-like" data-like-id="<?php echo $view_tweet['like_id']; ?>">
<!-- ★変更箇所2(ここまで)-->
<?php
if (isset($view_tweet['like_id'])) {
// いいね!がある場合
echo '<img src="../Views/img/heart.svg" alt="">';
} else {
// いいね!がない場合
echo '<img src="../Views/img/heart2.svg" alt="">';
}
?>
</div>
<!-- ★変更箇所3(ここから)-->
<div class="like-count js-like-count"><?php echo $view_tweet['like_count']; ?></div>
<!-- ★変更箇所3(ここまで)-->
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</div>
</body>
</html>
変更箇所1では、jQueryと追加したlike.jsを読み込んでいます。
変更箇所2では、「js-like」クラスを追加しています。これはJavaScriptで使います。
また、「data-like-id」属性を追加しています。これもJavaScriptで使います。
変更箇所3では、「js-like-count」クラスを追加しています。これもJavaScriptで使います。
続いて、like.jsに以下の内容を書きます。
htdocs/Twitter/Views/like.js
$(function () {
// いいね!がクリックされたとき
$('.js-like').click(function () {
const this_obj = $(this);
const like_id = $(this).data('like-id');
const like_count_obj = $(this).parent().find('.js-like-count');
let like_count = Number(like_count_obj.html());
if (like_id) {
// いいね!取り消し(カウントを減らす)
like_count -= 1;
like_count_obj.html(like_count);
this_obj.data('like-id', null);
// いいね!ボタンの色を変更
$(this).find('img').attr('src', 'img/heart2.svg');
} else {
// いいね!付与(カウントを増やす)
like_count += 1;
like_count_obj.html(like_count);
this_obj.data('like-id', true);
// いいね!ボタンの色を変更
$(this).find('img').attr('src', 'img/heart.svg');
}
});
})
まずは「$(function() { … })」の箇所に着目して下さい。
これは、「このJavaScriptファイル(ここではlike.js)がブラウザに読み込まれた瞬間に実行される」という意味になります。すなわち、Webページが表示された瞬間にこのfunctionの中身が実行されます。これは覚えるしかありません。
次に「$(this)」に着目して下さい。
文字通り「これ」という意味で、clickなどの対象としているものを指し、ここでは「$(‘.js-like’)」をもつHTML要素を指します。すなわち「<div class=”like js-like” data-like-id=”<?php echo $view_tweet[‘like_id’]; ?>”>」を指します。
「<div class=”like js-like” data-like-id=”<?php echo $view_tweet[‘like_id’]; ?>”>」=$(this)です。これが変数this_objに入ります。
次に「$(this).data(‘like-id’)」に着目して下さい。$(this)は上記の通りです。
「.」は「~の中の」という意味でしたね。すなわち「<div class=”like js-like” data-like-id=”<?php echo $view_tweet[‘like_id’]; ?>”>」の中の、という意味になります。
data(‘like-id’)は、data属性の値を指します。すなわち上記のdiv要素の中の「data-like-id」属性の値を指します。HTMLでは「data-like-id」と書き、JavaScriptでは「data(‘like-id’)」と書いてアクセスします。これは覚えるしかありません。
「data-like-id」属性の値は、イコールの後の「<?php echo $view_tweet[‘like_id’]; ?>」であり、PHPプログラム実行後は「1」や「2」といった値になります。
よって、「$(this).data(‘like-id’)」=「1」や「2」といった値になります。
次の「$(this).parent().find(‘.js-like-count’)」は下図のようなイメージになります。
parent()はJavaScriptの関数で、親要素を取得します。
find()もJavaScriptの関数で、当該要素以下の要素を検索します(引数を指定すると、引数と合致する要素を検索します)。
「like_count_obj.html()」は、「<div class=“like-count js-like-count”>1</div>」の(HTMLの)値を取得するJavaScriptの関数です。この例だと「1」が取得できます。
HTML上の1などの値は、基本的には文字列なのです。JavaScript上で数字と扱いたい場合、JavaScriptの関数であるNumber()を使って、文字列から数字に変換をしています。
次の「if (like_id) { … }」では、変数like_idに値が入っているかを確認しています。
値が入っていなければelseに進みます。
次の「like_count_obj.html(like_count)」に着目して下さい。
like_count_objには「<div class=“like-count js-like-count”>値</div>」が入っているのでしたね。「html(like_count)」は、HTMLの値を(変数like_countに入っている値で)書き換えます。
例えば、変数like_countに「0」が入っていれば、「<div class=“like-count js-like-count”>0</div>」となるわけです。
次の「this_obj.data(‘like-id’, null)」に着目して下さい。
this_objには「<div class=”like js-like” data-like-id=”値”>」が入っているのでしたね。data(‘like-id’)とすると、HTML属性data-like-idの値が取得できるのでした。一方、data(‘like-id’, 値)とすると、HTML属性data-like-idに値が設定できます。ここではnullを設定しています。
次の「$(this).find(‘img’).attr(‘src’, ‘img/heart.svg’)」は下図のようなイメージになります。
find(‘img’)で、img要素を探しています。
attr()はJavaScriptの関数で「attribute」の略です。属性を指します。一つ目の引数で具体的な属性名を指定し、二つ目の引数で値を指定すると当該属性の値を設定することができます。ここでは「img要素の属性srcの値を’img/heart.svg’で設定している」という意味になります。
ここまで出来たら、変更内容をコミットし、GitHubにプッシュして下さい。
本節の説明は以上になります。