【連載】CPIエバンジェリストのお悩み相談室④
JavaScriptでクリックした要素を検出し、classを付与する方法(後編)
>>> 前編はこちら
[現在のソースコード]
<html>
<head>
<title>TEST</title>
<meta charset="UTF-8">
<style type="text/css">
.btn{
width: 200px;
height: 30px;
margin: 5px; outline: none;
}
.active{
background-color: #666;
}
</style>
</head>
<body>
<button class="btn">ボタン1</button>
<button class="btn">ボタン2</button>
<button class="btn">ボタン3</button>
<script>
// ボタンのDOM要素を取得
var btn = document.getElementsByClassName('btn');
// ボタンの個数分ループ
// 変数「i」に現在のループ回数が代入される
for (var i = btn.length - 1; i >= 0; i--) {
// 各ボタンをイベントリスナーに登録
btn[i].addEventListener("click", function(){
// activeクラスの追加と削除
// thisは、クリックされたオブジェクト
this.classList.toggle('active');
});
}
</script>
</body>
</html>
ボタンの個数分ループしているfor文から、addEventListnerを外します。
// ボタンのDOM要素を取得
var btn = document.getElementsByClassName('btn');
// ボタンの個数分ループ
// 変数「i」に現在のループ回数が代入される
for (var i = btn.length - 1; i >= 0; i--) {
btnAction(btn[i],i);
}
function btnAction(btnDOM,btnId){
// 各ボタンをイベントリスナーに登録
btnDOM.addEventListener("click", function(){
// activeクラスの追加と削除
// thisは、クリックされたオブジェクト
this.classList.toggle('active');
});
}
</script>
その中に、イベントリスナーと、classList.toggleを入れています。
For文には、作成したbtnAction()関数の呼び出しを追加します。 btnAction()呼び出し時に、各ボタンの要素 btn[i]と、現在のループ番号 i を引数に渡しています。クリック時のアクションを関数化しましたが、処理の動きは変わりません。
■Step2:
ボタンの個数分ループしているfor文から、addEventListnerを外します。
btnAction() 関数を修正します。
// 各ボタンをイベントリスナーに登録
btnDOM.addEventListener("click", function(){
// activeクラスの追加と削除
// thisは、クリックされたオブジェクト
this.classList.toggle('active');
// クリックされていないボタンにactiveがついていたら外す
for (var i = btn.length - 1; i >= 0; i--) {
if(btnId !== i){
if(btn[i].classList.contains('active')){
btn[i].classList.remove('active');
}
}
}
})
}
for (var i = btn.length - 1; i >= 0; i--) {
「btnId」 はbtnAction()の呼び出し時に受け取った番号で、クリックされたボタンの番号が入っています。「i」には現在のループ番号入ります。よって、下記のif文はクリックされたボタン以外の場合に真になります。
if(btnId !== i){
クリックされた以外のボタンの場合、classList.contains(‘active’) を使い、ボタンにactiveクラスが付与されていないか確認します。
if(btn[i].classList.contains('active')){
btn[i].classList.remove('active');
} activeクラスが付与されていたら、classList.remove('active')でactiveクラスを削除します。
以上で、前回から行っているプログラムは終了しました。
完成したコードはこちらです。
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
.btn{
width: 200px;
height: 30px;
margin: 5px;
outline: none;
}
.active{
background-color: #666;
}
</style>
</head>
<body>
<button class="btn">ボタン1</button>
<button class="btn">ボタン2</button>
<button class="btn">ボタン3</button>
<script>
// ボタンのDOM要素を取得
var btn = document.getElementsByClassName('btn');
// ボタンの個数分ループ
// 変数「i」に現在のループ回数が代入される
for (var i = btn.length - 1; i >= 0; i--) {
btnAction(btn[i],i);
}
function btnAction(btnDOM,btnId){
// 各ボタンをイベントリスナーに登録
btnDOM.addEventListener("click", function(){
// activeクラスの追加と削除
// thisは、クリックされたオブジェクト
this.classList.toggle('active');
// クリックされていないボタンにactiveがついていたら外す
for (var i = btn.length - 1; i >= 0; i--) {
if(btnId !== i){
if(btn[i].classList.contains('active')){
btn[i].classList.remove('active');
}
}
}
})
}
</script>
</body>
</html>
では、最後にステップアップとして次の要件に合わせてソースコードを修正してみましょう。
練習問題(1)
クリックした時に、buttonタグに対して activeクラスを追加しました。下記のようにbuttonタグの中にspanタグを追加し、spanタグに対してactiveクラスを追加してみましょう。
<button class="btn"><span>ボタン1</span></button>
ヒント:
buttonタグの下のspanタグのDOM要素取得は、btnDOM.addEventListener("click", function(){の下に console.dir(this);を設置すると分かりやすいですが、childrenプロパティに直下のタグがDOMとして取得することができます。
現在ボタンのクリックを検出しクラスの追加と削除をしています。ボタン以外がクリックされた時(bodyタグや、その他の要素)に、activeクラスが付いていたら、activeを削除しましょう。
ヒント:
htmlタグに対して、イベントリスナーを登録します。クリック時に呼び出される関数には、MouseEventオブジェクトが引数として受け取れるので、ボタン以外がクリックされたことを判断し、処理を行います。
html[0].addEventListener("click", function(e){
// マウスイベントの出力
console.dir(e);
})
実行結果:
練習問題(1):答え
this.classList.toggle('active'); を
this.children[0].classList.toggle('active'); に変更する。
練習問題(2):答え
html[0].addEventListener("click", function(e){
// HTMLがクリックされたら
if(e.path[0].nodeName === 'HTML'){
// ボタンの個数分ループ
for (var i = btn.length - 1; i >= 0; i--) {
if(btn[i].classList.contains('active')){
btn[i].classList.remove('active');
}
}
}
})
e.path で、クリックされた階層のパスを確認することができます。例えばボタンがクリックされた場合、e.path[0] は、ボタン要素が入ります。
さて、練習問題は解けましたでしょうか。読んでもわからないという方のために、レンタルサーバー「CPI」のスタッフブログでJavascriptのオブジェクトを解説した動画を公開しました!よろしければ、こちらも合わせてご覧ください。
url. http://shared-blog.kddi-web.com/webinfo/220
[筆者プロフィール]
阿部 正幸(あべ まさゆき) | KDDIウェブコミュニケーションズ/エバンジェリスト
システム開発会社で大規模なシステム開発を経験後、Web制作会社でプログラマー兼ディレクターとして従事。その後、KDDIウェブコミュニケーションズに入社、レンタルサーバーCPIのプロダクトマネージャーに就任。ACE01、SmartReleaseをリリース後、現職の「エバンジェリスト」としてWeb制作に関する様々なイベントに登壇。Drupal(g.d.o Japan)日本コミュニティー、HTML5 funなどに所属し、OSSを世に広げる活動やWeb制作に関する情報を発信している。
●CPIスタッフブログ
URL:http://shared-blog.kddi-web.com/
● CPI LINE@のご案内
http://shared-blog.kddi-web.