教材の内容に関係のない質問や教材とは異なる環境・バージョンで進めている場合のエラーなど、教材に関係しない質問は推奨していないため回答できない場合がございます。
その場合、teratailなどの外部サイトを利用して質問することをおすすめします。教材の誤字脱字や追記・改善の要望は「文章の間違いや改善点の指摘」からお願いします。
このパートでは jQuery を使った実装をしてみましょう。
本パートでは jQuery を使って Twitter 風フォローボタンを実装していただきます。実際にリアル DOM を操作してみて、何が問題なのかを明確にします。
サーバーから受け取った HTML に対して jQuery を使ってリアル DOM を操作します。
では実際に進めていきましょう。
はじめにプロジェクトを作成します。任意のディレクトリで下記の構成を作成してください。
Copied!└── src
├── index.html
├── script.js
└── style.css
以下の HTML ファイルは、サーバーサイド(例えば PHP など)からもらった HTML を想定しています。ではsrc/index.html
を以下のように編集してください。
index.html
html123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 Copied!<html lang="ja">
<head>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<main>
<div id="app">
<ul class="accountList">
<li
class="accountList__item js-account-item"
data-follow="false"
data-id="1"
>
<div>
<div class="account__summary">
<div>
<p class="account__name">リオネル・メッシ</p>
<p class="account__team">FCバルセロナ</p>
</div>
<div>
<button type="button" class="js-follow-btn followBtn">
フォローする
</button>
</div>
</div>
<p class="account__description">
アルゼンチンサンタフェ州ロサリオ出身のイタリア系アルゼンチン人サッカー選手。リーガ・エスパニョーラ・FCバルセロナ所属。アルゼンチン代表。ポジションはフォワード
(wikipedia)
</p>
</div>
</li>
<li
class="accountList__item js-account-item"
data-follow="true"
data-id="2"
>
<div>
<div class="account__summary">
<div>
<p class="account__name">クリスティアーノ・ロナウド</p>
<p class="account__team">Juventus</p>
</div>
<div>
<button type="button" class="js-follow-btn followBtn">
フォロー中
</button>
</div>
</div>
<p class="account__description">
ポルトガル・フンシャル出身のサッカー選手。セリエA・ユヴェントスFC所属。ポルトガル代表。ポジションはフォワード
(wikipedia)
</p>
</div>
</li>
<li
class="accountList__item js-account-item"
data-follow="false"
data-id="3"
>
<div>
<div class="account__summary">
<div>
<p class="account__name">ネイマール</p>
<p class="account__team">パリサンジェルマン</p>
</div>
<div>
<button type="button" class="js-follow-btn followBtn">
フォローする
</button>
</div>
</div>
<p class="account__description">
ブラジル・サンパウロ州モジ・ダス・クルーゼス出身のサッカー選手。ブラジル代表。リーグ・アン・パリ・サンジェルマンFC所属。ポジションはフォワード
(wikipedia)
</p>
</div>
</li>
</ul>
</div>
</main>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="script.js"></script>
</body>
</html>
簡単に説明
この部分で style をリンクさせています。実際の style.css
は後ほど記載いたします。
html1 Copied!<link rel="stylesheet" href="style.css" />
今回は data-follow (data 属性)を使用して DOM から情報を受け取るようにしています。
html123 Copied!<li class="accountList__item js-account-item" data-follow="false" data-id="1">
// 各アカウント
</li>
次に、ボタンをクリックしたら フォロー・フォロー解除解除ができるように js 用の class を指定しています。
html123 Copied!<button type="button" class="js-follow-btn followBtn">
フォローする
</button>
次に style.css
ですが、こちらは見た目だけになりますので、詳細な説明は省略させていただきます。下記コードをコピー & ペーストしていただければ大丈夫です。
css12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 Copied!/** 共通スタイル **/
html {
font-size: 62.5%;
}
body {
background: #fafafa;
font-size: 1.6rem;
color: #222;
}
ul {
list-style: none;
margin: 0;
padding: 0;
}
p {
margin: 0;
padding: 0;
}
/** アカウント一覧スタイル **/
#app {
width: 100%;
max-width: 640px;
margin: 100px auto;
padding: 0;
background: #fff;
border: solid 1px #e0e0e0;
}
.accountList {
padding: 0;
margin: 0;
}
.accountList__item {
position: relative;
padding: 1rem;
border-bottom: solid 1px #e0e0e0;
}
.accountList__item:last-child {
border: 0;
}
.account__summary {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.account__name {
font-weight: 700;
}
.account__team {
font-size: 1.2rem;
color: #646464;
}
.account__description {
font-size: 1.4rem;
}
.followBtn {
display: inline-block;
min-width: 100px;
border: 0;
touch-action: manipulation;
cursor: pointer;
padding: 0 1rem;
height: 32px;
line-height: 32px;
font-weight: 800;
outline: none;
position: relative;
border: solid 1px #e0e0e0;
background: #fff;
color: #222;
border-radius: 16px;
}
.followBtn:hover {
background: #e0e0e0;
}
.followBtn.isFollow {
background: rgb(29, 161, 242);
border: solid 1px rgb(29, 161, 242);
color: #fff;
}
.followBtn.isFollow:hover {
opacity: 0.7;
}
次に script.js を実装します。以下のコードを追加してください。
javascript1234567891011121314151617181920212223242526272829 Copied!$(function () {
$(".js-account-item").each(function () {
var $this = $(this);
var $thisData = $this.data();
if ($thisData.follow) {
$this.find(".js-follow-btn").addClass("isFollow");
}
});
$(".js-follow-btn").on("click", function () {
var $this = $(this);
var $accountItem = $this.parents(".js-account-item");
var $thisData = $accountItem.data();
if ($thisData.follow) {
// ajax
$this.removeClass("isFollow");
$this.text("フォローする");
$accountItem.data("follow", false);
} else {
// ajax
$this.addClass("isFollow");
$this.text("フォロー中");
$accountItem.data("follow", true);
}
});
});
細かくみていきます。
ブラウザで表示されるたびに、下記 html の data-follow="false"
でアカウント一人一人がすでにフォローしているのかどうかをチェックしています。
そして true
の場合には、ボタンに対して isFollow
クラスを追加しています。
html123 Copied!<li class="accountList__item js-account-item" data-follow="false" data-id="1">
// 各アカウント
</li>
javascript1234567 Copied!$(".js-account-item").each(function () {
var $this = $(this);
var $thisData = $this.data();
if ($thisData.follow) {
$this.find(".js-follow-btn").addClass("isFollow");
}
});
次にボタンをクリックをした場合に フォローかフォロー解除か切り替える必要がありますね。
下記の部分でクリックをしたら、data-follow
が true であれば
isFollow
クラスを削除ということをしています。data-follow
が false の場合は全く正反対のことをしています。
さらに今回は割愛させていただいていますが、実際のプロダクトであれば ajax を使ってサーバーサイドにフォロー・フォロー解除の変更がされたことを送信しなければいけません。
javascript12345678910111213141516171819 Copied!$(".js-follow-btn").on("click", function () {
var $this = $(this);
var $accountItem = $this.parents(".js-account-item");
var $thisData = $accountItem.data();
if ($thisData.follow) {
// ajax
$this.removeClass("isFollow");
$this.text("フォローする");
$accountItem.data("follow", false);
} else {
// ajax
$this.addClass("isFollow");
$this.text("フォロー中");
$accountItem.data("follow", true);
}
});
ではブラウザで表示をさせてみましょう。任意のブラウザに index.html をドラッグ & ドロップをしてみましょう。
以下のように表示され、フォローボタンが作動していれば大丈夫です。
おさらいとしてフォロー・フォロー解除の流れをもう一度確認しましょう。
となっています。もう少し噛み砕いていうと見た目を基準に操作していることがわかります。jQuery でも昨今のフロントエンドフレームワークと同じことができることがわかったかと思います。ですが、その見た目(DOM)基準に操作することに問題点があります。
見た目を操作をもう少し専門的に言うと DOM 操作と言います。では、その DOM 操作の問題点とはなんでしょう。
と言うことが挙げられます。
今回の実装を思い出してみましょう。HTML に直接記述されている data 属性を元にフォローかどうかの判定をしていました。
html123 Copied!<li class="accountList__item js-account-item" data-follow="false" data-id="1">
// 各アカウント
</li>
HTML の作りに依存してしまっていますよね。極端な話アカウントのデータと HTML が紐付きすぎてしまっていて、ロジックと UI を分離することが難しいことが伺えます。
実際の開発でしたら、例えば既存サービスをリデザインをするときに問題が表面化しやすいです。
jQuery の場合、今回は規模も小さいですが、 一例として、以下のコードでは hoge
クラスの要素の子要素である button
をクリックした時の動作を追加しています。
リデザインでどうしても HTML の構造を変更しなければいけない場合どうでしょう?具体的には button
が hoge
の子要素では無くなっていたら・・・
これだけでボタンが動作しなくなってしまいますよね。
javascript12345 Copied!$(".hoge")
.children("button")
.on("click", function () {
// 何か処理
});
html12345678 Copied!<div class="hoge">
<button type="button">送信</button>
</div>
↓
<div class="hoge">
下記のボタンをクリック
</div>
<button type="button">送信</button>
今回の実装ではフォローかどうかの状態しかありませんでした。なので、そんなに複雑にはなっていませんが、これがもっと大規模な WEB アプリケーションではどうでしょう。
同じように Twitter の場合でしたら、メッセージが来ていたら、通知が来ていたら新しいツィートが来たらなどの状態がありますね。そうすると jQuery、もっと突き詰めると リアル DOM での操作では状態の管理が難しくなってしまいます。おそらく人間では全体を把握することが不可能なほど・・・。
1 章では jQuery を使い、大規模な WEB アプリケーションでの DOM 操作による状態の管理の難しさを説明しました。次の章では仮想 DOM を使ったライブラリーである React を使い同じように Twitter 風フォローボタンを実装していただきます。
お疲れさまでした!