Webチームのebiです。
これまで、初心者がWeb開発のスタートラインにすら立たせてもらえない怒りと悲しさをぶちまける記事しか書いてこなかったので、そろそろ開発に近い記事を書きたいと思った今日この頃です。
そんな訳で今回はJavaScript(jQuery)で記事を書きます。僕自身、業務でJavaScriptだけを酷使してきたわけではないので、初心者向けな入門編記事です。
JavaScriptってかじる人が多いせいか、とんでもないコードがネット上には放置されているので、意味を理解せずにコピペしてると痛い目を見ます(と言うか痛い目を見ました)。
今回の記事で紹介するものは、実際に自分がフォーム作成とかで過去に書いたコードを元ネタにしているので、ある程度は実用的だと思います。あとJavaScriptとは銘打ってますが、jQueryの文法で書いていきます。
ちゃんとしたJavaScript(jQuery)の書き方に慣れてくると、大体のことならちょっと追加で必要なことを調べれば何とかなりそうな自信が付きます。今回の記事では、なるべく色々な書き方を紹介することも意識します。
大事なのは動作のスイッチになる対象、変更を加えたい対象、をどう指定するのか。どんな風に書けば期待通りの変化を与えられるのかを理解することだと思います。
過剰なコメント付けといたので、よかったら参考にしてみてください。
JavaScriptを使って、HTML、CSSを動的に変えてみる
下のデモのselectを変えると、そのすぐ下にある別の部品の見た目が動的に変わります。
選んだ選択肢に応じて、他の選択肢の内容や見せ方を変えるのに応用できます。
HTMLのコード
<div>
<select name="sample-select">
<option>その1</option>
<option>その2</option>
<option>その3</option>
</select>
<div id="box" style="width:200px; height:200px; background-color: blue; color:white; display: flex; align-items: center; justify-content: center;">その1</div>
</div>
JavaScriptのコード
$('select[name=sample-select]').change(function() { // 対象のselectの値が変わったら実行
// div #boxの色を変えてみる
if($(this).prop('selectedIndex') === 0) { // selectedIndexは何番目のoption要素なのかを表す値
$('#box').css('background-color','blue'); // cssを制御する
}else if($('option:selected', this).text() === 'その2') { // 今度はoptionの項目名で分岐させてみる
$('#box').css('background-color','red');
}else{
$('#box').css('background-color','green');
}
// .text()に値を入れると、対象の文字情報を変更できる
$('#box').text($(this).val()); // $('option:selected', this).text()は$(this).val()でも書けちゃう
});
prop()とattr()は似ているけど違う使い方をすること、古い書き方がネットに残っていることがあるので注意します(もちろん騙された)。
$('option:selected', this) は今の要素(this)の子要素であるoptionで、さらにselectedな状態のものを指定する書き方です。
JavaScriptの == は厳密な比較ではないので、 === を使う方が無難です(まさかりを投げられる)。
JavaScriptを使って、バリデーションしてみる
バリデーションを自力で全部やるのは辛いと思うので、素のHTMLで構成されたホームページとかだったとしても、jQuery-Validation-Engineみたいな便利なライブラリを積極的に使用することをお勧めしますけどね。
足りない機能をちょっと足すために、自力でそれっぽく動くコードを書くことはありました。
デモです。半角数字以外を入力すると、画面上の適当なところをクリックしたタイミングで注意されます。
インラインだと疑似要素が使えないので、似非jQuery-Validation-Engineになっちゃいました。提出時のバリデーションもanimate()を上手く使うと間違った項目まで移動させたりもできます。アニメグッズ専門店のことではないです。
HTMLコード
<div style="position:relative;">
半角数字を入力してね。<br>
<div id="validation" style="opacity: 0.87; position: absolute; width: 230px; top:50px; left: 5px; visibility: hidden;">
<div style="width: 100%; background: #c43939; position: relative; color: #fff; min-width: 120px; font-size: 11px; padding: 4px 10px 4px 10px; border-radius: 6px; cursor: pointer;">* 半角数字じゃないよ!</div>
</div>
<input type="text" name="number-input">
</div>
JavaScriptコード
$("input[name='number-input']").blur(function(){ // 対象のinputに入力されたら動作する
if(!/^[0-9]+$/.test($(this).val())) { // 正規表現でチェックします。正規表現を勉強すればバリデーションの幅が広がります
$('#validation').css('visibility', 'visible'); // validation用のdivの表示をCSSで制御します
} else {
$('#validation').css('visibility', 'hidden');
}
});
$("#validation").on("click", function() { // 表示したメッセージはクリックされると消えるようにする
#(this).css('visibility', 'hidden');
}
!/^[0-9]+$/.test($(this).val() は !$(this).val().match(/^[0-9]+$/) と書いても同じような動作になります。
しかし、 .match() は、正規表現に一致する結果を含む配列を取得するか、一致しない場合はnull が返ってきます。
true or false を返す .test() の方が速いらしいし、バリデーションの目的には適してそうです。
書き方が逆になるので注意です(書き直す時に間違えた)。
JavaScriptを使って、フォームの記入欄を動的に追加、削除する
今回の記事の本編(のつもり)です。何気に大変じゃないですか?
業務外で軽い気持ちでやってみようとして涙目になりました。
入社間もない頃だったので、JavaScript慣れてないし継ぎ接ぎで汚くても動けばいいや、で終わっていたのでリファクタリングと言うかリベンジしてみました。
名前 | フリガナ |
---|---|
HTMLコード
<table id="sample-form">
<tr class="title">
<th>名前</th>
<th>フリガナ</th>
</tr>
<tr class="input">
<td><input type="text" name="form1[0][name]"></td>
<td><input type="text" name="form1[0][furigana]"></td>
</tr>
</table>
<div style="text-align:center;">
<button class="add-btn">記入欄を追加</button>
<button class="delete-btn">記入欄を削除</button>
</div>
同様の記入欄が複数箇所あることを想定しているので、name属性は配列にしています。送った後は、$_POST['form1'][0]['name']とかで取り出します。
JavaScriptコード
$('.add-btn').click(function(){ // 追加ボタンが押されると実行
$('#sample-form tr:eq(1)').clone().appendTo('#sample-form'); // 最初の記入欄を複製して最後に足す
$('#sample-form tr:last-child input').each(function(){ // 複製した記入欄のinput部分をそれぞれ微調整する
$(this).val(''); // そのままだと最初の記入欄に記入した内容も複製されるので、初期化する
count = $('#sample-form .input').length-1; // 何人目の記入欄なのかを取得する
$(this).attr('name',$(this).attr('name').replace('0',count)); // 正しい数字に置き換える
});
});
$('.delete-btn').on('click', function() { // 削除ボタンが押されると実行
if($('#sample-form .input').length > 1) { // 記入欄が全てなくならないようにチェックする
$('#sample-form tr:last-child').remove(); // 最後の記入欄を一つ消す。
}
});
挿入する素材のテンプレートを用意して作ろうとすると、下手したら似たようなコードを別々で量産してしまうことになります。
フォームの記入欄を追加すると言うことは、複製する元になる素材は必ず存在している訳なので、clone()して、name属性等を微調整するのがシンプルだし共用できそうです。
ちなみに、↑のコードでは .click()と.on('click',function()) の両方を同じ用途で使っています。
今回のコードだとどちらでも問題ないんですが、例えば削除ボタンを、それぞれの記入欄ごとに付けたい場合があると思います。
この場合、削除ボタンも後から複製することになるんですが、JavaScriptで動的に追加した要素はイベントのトリガーにはなれません。同じように書けばいいと思っていると、追加した削除ボタンが思い通りに動いてくれない場合があるので、注意してください(もちろん経験した)。
解決するには、最初から存在する親要素を先に絡めるのが重要です。
$(document).on('click','.delete-btn',function())
や
$('#sample-form').on('click','.delete-btn',function())
と書き始めると、追加した要素も動いてくれるはずです。
番外:アコーディオンメニュー編
jQueryを使って、アコーディオンメニューってHTML、CSS、JavaScriptあたりをまとめたWeb開発入門書の定番だったりしませんか?
何を隠そう、僕も入社前にフラッと買ってみた本でやりましたし。
まずは以下のデモを見ましょう。見出しをクリックすると、隠れていた項目が出てきます。
見出し1
見出し2
HTMLのコード
<div>
<p class="accordion" style="text-decoration: underline;">見出し1</p>
<ul style="display:none;">
<li>項目1-1</li>
<li>項目1-2</li>
</ul>
<p class="accordion" style="text-decoration: underline;">見出し2</p>
<ul style="display:none;">
<li>項目2-1</li>
<li>項目2-2</li>
<li>項目2-3</li>
</ul>
</div>
JavaScriptのコード
$(".accordion").on("click", function() {
$(this).next("ul").slideToggle();
});
入門書では、slideUpとslideDownを使った記憶があったんですけど、slideToggleだけで書けると言う事実はちょっと衝撃的でした。短いコードの方が簡単そうですよね。
おわり
JavaScriptもいいですが、CSSアニメーションもそこそこ使えるようになりたいです。