質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

3回答

1271閲覧

クリックされた要素のインデックスの取得について

T.Takeda

総合スコア29

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2019/06/14 23:08

前提・実現したいこと

果物のカウントが出来るツールを作りたいです。

発生している問題

一応は以下のコードで動くのですが、JavaScriptにおいて、プラスボタンとマイナスボタンのaddEventListenerを果物の品名の数だけ書かなければならない状況となっています。
クリックされたボタンのインデックスを取得することができれば、各ボタンにつきaddEventListenerを1つずつで済むのではと考えております。
そこで、クリックされたボタンのインデックスの取得方法を教えていただけますでしょうか。
また、よりベターな書き方があればアドバイスいただきたいです。

よろしくお願いします。

該当のソースコード

HTML

1<section class="items"> 2 <ul> 3 <div class="item"> 4 <li>みかん</li> 5 <div class="count"> 6 <div id="plus" class="icon">+</div> 7 <div id="num">0</div> 8 <div id="minus" class="icon">-</div> 9 </div> 10 </div> 11 <div class="item"> 12 <li>りんご</li> 13 <div class="count"> 14 <div id="plus" class="icon">+</div> 15 <div id="num">0</div> 16 <div id="minus" class="icon">-</div> 17 </div> 18 </div> 19 <div class="item"> 20 <li>ぶどう</li> 21 <div class="count"> 22 <div id="plus" class="icon">+</div> 23 <div id="num">0</div> 24 <div id="minus" class="icon">-</div> 25 </div> 26 </div> 27 </ul> 28</section> 29

CSS

1li{ 2 height: 40px; 3 line-height: 40px; 4 text-align: center; 5 margin-right: 10px; 6 7} 8 9.count{ 10 display: flex; 11 align-items: center; 12} 13 14.item{ 15 display: flex; 16 margin:10px; 17} 18 19#num{ 20 width: 100px; 21 height: 30px; 22 border-radius: 5px; 23 border: 1px solid #ddd; 24 line-height: 30px; 25 text-align: center; 26 margin: 0 5px; 27} 28 29.icon{ 30 width: 20px; 31 height: 20px; 32 line-height: 20px; 33 text-align: center; 34 border-radius: 50%; 35} 36 37#plus{ 38 background: pink; 39} 40 41#minus{ 42 background: skyblue; 43}

JavaScript

1const num = document.querySelectorAll('div#num'); 2 const plus = document.querySelectorAll('div#plus'); 3 const minus = document.querySelectorAll('div#minus'); 4 //今回の質問部分↓// 5 plus[0].addEventListener('click', () => { 6 num[0].textContent++; 7 }); 8 9 minus[0].addEventListener('click', () => { 10 num[0].textContent--; 11 }); 12 13 plus[1].addEventListener('click', () => { 14 num[1].textContent++; 15 }); 16 17 minus[1].addEventListener('click', () => { 18 num[1].textContent--; 19 }); 20 21 plus[2].addEventListener('click', () => { 22 num[2].textContent++; 23 }); 24 25 minus[2].addEventListener('click', () => { 26 num[2].textContent--; 27 });

試したこと

indexOfやparentNodeを使って試行錯誤してみましたが、うまくいきませんでした。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/06/14 23:29 編集

jQuery は使えないのでしょうか? 使えないとすると、リスナーは上位の要素にアタッチして、バブリングで上がってくるイベントを捕捉して処置するとか? (一つのリスナーで処置する方法はすでに回答が出ています)
yasutomi

2019/06/15 07:24

idならdocument.querySelectorAll('div#num')ではなく document.getElementById('num') としたほうが 処理が早く、わかりやすいですので修正したほうが良いです。
T.Takeda

2019/06/15 20:58

アドバイスありがとうございます。 jQueryは使わずに作成したいと考えています。 idについても、classへ変更したいと思います。
guest

回答3

0

<div>の中にdata-index='1'のように値を埋め込んで、クリックイベントでe.target.dataset.indexのように参照する方法が考えられます。


本題ではありませんが、idは同じ文書内で重複してはいけません。きちんと切り分けるようにしましょう。

投稿2019/06/14 23:14

maisumakun

総合スコア145121

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

T.Takeda

2019/06/15 21:27

ご回答ありがとうございます。 理解が追いつけておらず、申し訳ございませんが対処方法についてもう少し教えてください。 `data-index='1'`はボタンのdivに追加すれば、各ボタンにインデックスが付けられるという理解で合っていますでしょうか。 また、クリックイベントで`e.target.dataset.index`を参照するにはどの様に書いたら良いでしょうか。 現在、プラスボタンにイベントリスナーを設定するために、`plus[0].addEventListener('click',〜`と書いているのですが、初めの`plus[0]`をどの様に修正したら良いのかわからず悩んでおります。。。 よろしくお願いします。
guest

0

原因

indexOfやparentNodeを使って試行錯誤してみましたが、うまくいきませんでした。

  • querySelectorAll が返すNodeListは配列(Array)ではないので、Array.prototype.indexOf を持ちません
  • parentNode から num を辿る発想は間違っていませんが、idは一意ですので、document.querySelectorAll('div#num') は**一番初めに存在するid="num"を持つ要素ノード(単体)**を返します

対策

「index値取得」「ループ処理」が不要な方法をお勧めします。

  1. plus,minus,num のid属性値をclass属性値に変更
  2. document.querySelector('.items>ul').addEventListener
  3. event.target.classList.contains で plus,minus 判定
  4. event.target.parentNode.querySelector で num を参照し、textContent をインクリメントorデクリメント

セマンティクス

セマンティクス的には plus,minus はボタンなので、input要素であるべきと考えます。
(デザインはCSSで調整しましょう)

HTML

1<input type="button" name="sign" value="plus" /> 2<input type="button" name="sign" value="minus" />

HTMLがclass属性値からvalue属性値に変わるので、それを確認するコードも変わります。
また、numは数値を入力する要素とも解釈出来ますので、input要素で代替する手段が考えられます。

HTML

1<input type="number" name="num" />

こうなると、[+], [-] ボタンがデフォルトで付与されていますので、plus,minus処理が不要になります。

Re: T.Takeda さん

投稿2019/06/15 22:38

編集2019/06/15 22:41
think49

総合スコア18156

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

T.Takeda

2019/06/16 22:00

ご回答ありがとうございます。 ご教示いただいた方法でもやりたかったことが実現でき、かつparentNodeに関する知識も深まり勉強になりました。
guest

0

ベストアンサー

こんにちは。

この回答では、ご質問の本題である

プラスボタンとマイナスボタンのaddEventListenerを果物の品名の数だけ書かなければならない状況

を解消するために

1. ボタンのインデクスを使う例

2. ボタンのインデクスを使わない例

の両方のコードを挙げますが、その前に、まずご質問にある HTMLとCSSを、以下の2点で修正します。

  • <li> の親要素は <ul> になるようにする。

  • id の値 plus, num, minus が複数の異なる要素に付与されているので、これらをクラスにする。

上記2点について、簡単な修正をしたHTMLとCSSが以下です。

html

1<section class="items"> 2 <ul> 3 <li> 4 <div class="item"> 5 <span class="name">みかん</span> 6 <div class="count"> 7 <div class="plus icon">+</div> 8 <div class="num">0</div> 9 <div class="minus icon">-</div> 10 </div> 11 </div> 12 </li> 13 <li> 14 <div class="item"> 15 <span class="name">りんご</span> 16 <div class="count"> 17 <div class="plus icon">+</div> 18 <div class="num">0</div> 19 <div class="minus icon">-</div> 20 </div> 21 </div> 22 </li> 23 <li> 24 <div class="item"> 25 <span class="name">ぶどう</span> 26 <div class="count"> 27 <div class="plus icon">+</div> 28 <div class="num">0</div> 29 <div class="minus icon">-</div> 30 </div> 31 </div> 32 </li> 33 </ul> 34</section> 35

css

1li { 2 height: 40px; 3 line-height: 40px; 4 text-align: center; 5 margin-right: 10px; 6} 7 8.item { 9 display: flex; 10 margin: 10px; 11} 12 13.name { 14 margin-right: 12px; 15} 16 17.count{ 18 display: flex; 19 align-items: center; 20} 21 22.num { 23 width: 100px; 24 height: 30px; 25 border-radius: 5px; 26 border: 1px solid #ddd; 27 line-height: 30px; 28 text-align: center; 29 margin: 0 5px; 30} 31 32.icon { 33 width: 20px; 34 height: 20px; 35 line-height: 20px; 36 text-align: center; 37 border-radius: 50%; 38} 39 40.icon.plus { 41 background: pink; 42} 43 44.icon.minus { 45 background: skyblue; 46} 47

上記のように修正したHTMLとCSS に対して、意図している動作を実現するための javascript を以下に挙げます。

1. ボタンのインデクスを使う例

以下のコードで btnIndex にボタンのインデクスが(0始まりで)入ってきます。

javascript

1document.querySelectorAll('.icon').forEach((btn, btnIndex) => { 2 3 btn.addEventListener('click', () => { 4 const numDiv = document.querySelectorAll('.num')[Math.floor(btnIndex / 2)]; 5 numDiv.textContent = (+numDiv.textContent) + (btnIndex % 2 ? -1 : 1); 6 }); 7 8}); 9

以下は、上記を動作確認するために jsFiddleに上げたものです。

2. ボタンのインデクスを使わない例

.count にクリックハンドラを設定し、 イベントターゲットが .icon の場合に、当該の .count に含まれる .num のカウンターを増減する処理を書きます。

javascript

1document.querySelectorAll('.count').forEach(counter => { 2 3 counter.addEventListener('click', function(e) { 4 const { classList } = e.target; 5 if (classList.contains('icon')) { 6 const numDiv = counter.querySelector('.num'); 7 if (classList.contains('plus')) 8 numDiv.textContent ++; 9 else if (classList.contains('minus')) 10 numDiv.textContent --; 11 } 12 }); 13 14});

  

    

以上、参考になれば幸いです。

追記

コメントから頂きました質問に回答します。

(1) 単項加算について

(+numDiv.textContent)の書き方は初めてみたのですが、もし特別な表記方法なのであれば名前を教えていただけますか。

**単項加算(Unary plus) **です。

自身で調べてみたいと思います。

以下が参考になると思います。

丁寧に書けば parseInt(numDiv.textContent) とするところですが、 (コードの読みやすさはさておき、)+numDiv.textContent と短いコードで済ませることができます。

なお、試しにnumDiv.textContentとに変えて実行してみたところ、ボタンを押すたびにnumDiv内に"1"というテキストが追加されました。

はい。そのように変えたりして試してみることは大変よい事です。単項加算を取ってしまって、 numDiv.textContentとすると

javascript

1numDiv.textContent = numDiv.textContent + (btnIndex % 2 ? -1 : 1);

となるわけですが、たとえば <div class="num">0</div> となっているとき、numDiv.textContent は、文字列(String)の '0' を返します。ここから + をクリックしたとすると (btnIndex % 2 ? -1 : 1) は、 数値(Number)の 1 となります。従って上記の右辺は

javascript

1'0' + 1

という加算を行うことになりますが、この結果は(期待している)数値の 1 にはならずに、 '0' + 11 が文字列の'1'として扱われて、 '0' + '1' という文字列の連結が行われて、結果は '01'という文字列になります。以下同様にして、+をクリックするたびに '1'、 ーをクリックするたびに '-1'という文字列が末尾に追加された文字列がnumDiv.textContent に入ってしまいます。これを意図する動作にするためには、numDiv.textContentに 文字列の'0' が入っているとき、数値の0が得られたらよいので 、 単項加算を使って +numDiv.textContentとしています。なお (+numDiv.textContent) と書いてるところの丸カッコ ( ) は無くても問題ないので、

javascript

1numDiv.textContent = +numDiv.textContent + (btnIndex % 2 ? -1 : 1);

でも意図通りに動きます。( ) をつけて、(+numDiv.textContent)としたのは、カッコが無いより多少読みやすくなるかな、ぐらいの考えでした。

(2) 条件 (三項) 演算子について

・条件 (三項) 演算子の記載についてですが、btnIndex % 2 ? -1 : 1は奇数がtrueで偶数がfalseということでしょうか。

はい。そうです。

そのモヤモヤを解消するには、 TruthyFalsy という用語を知っておくと整理できるかもしれません。

TruthyFalsy という言葉を使えば、 条件 (三項) 演算子 式 ? A : B では、 (を評価した結果の)値が Truthy であれば A、 Falsyであれば B となる、と言えます。たとえば空文字列 '' は、Falsy なので

javascript

1'' ? 10 : 20

の結果は 20 となります。また、

javascript

1[1,2,3].length ? 10 : 20

の結果は、 [1,2,3].length3で、 3 はTruthyなので 10 となります。

本題の

javascript

1btnIndex % 2 ? -1 : 1

についてですが、 この条件演算子の結果は、ボタンがクリックされたときの、現状の値に加算する値を表し、具体的には1-1 となります。-1 を加算するということは、つまり 1 を引くということです。

条件式の btnIndex % 2btnIndex を2で割った余りですので、 01 です。btnIndex % 20 のときは、条件式としては Falsy です。そのとき、ボタンは0始まりのインデクスが偶数の位置にあるということなので、現状でのデザインでは + ボタンのほうなので、加算する数値として : の後ろには 1 があるべきです。逆に btnIndex % 2 が1のとき、つまり条件式としてTruthy のとき、 btnIndex は奇数で、現状のデザインでは ー ボタンのほうなので 1を引きたいわけですから、加算する数値としては、: の前の値は -1 でなければなりません。

javascript

1btnIndex % 2 ? -1 : 1

をよく見ると、条件演算子の ? の後ろが、-1 : 1 となっていて、これはボタンの表示上の並びである、
+ 数 ーとは逆なので、ちょっと混乱するかもしれませんね。-1 : 1 ではなく 1 : -1 と、 ボタンの並びと同じにするには、btnIndex が偶数のときTruthyになる条件式になればよいので

javascript

1btnIndex % 2 === 0 ? 1 : -1

と書けばよいです。つまり押さえておくべきポイントは、

x が n で割り切れるとき、 x % n は、 ( 0 なので) 条件式としては Falthy になる。

ということです。T.Takedaさんが

感覚的に2で割り切れればtrueに感じてしまうのですが。。。

とおっしゃるように確かに直感的には 割り切れるときtrueという感じがしますが、割り切れるとき Truthy な式は x % n === 0 というふうに === 0 を追加しなければなりません。 コードを短くすることを求めると、 x % n ===0 ではなく、単に x % n と条件式に書きたいので、そうすると条件演算子の ? の後のA : BA には割り切れないときの値を書くことになります。

このあたりは好みなので、 読みやすさを優先して、btnIndex % 2 === 0 ? 1 : -1 を採用するのでもかまわないと思います。

回答のコードに書いた、

javascript

1numDiv.textContent = (+numDiv.textContent) + (btnIndex % 2 ? -1 : 1);

は、parseInt(numDiv.textContent)とせずに単項加算を使ったり、 btnIndex % 2 === 0 としないで、単にbtnIndex % 2 を条件式にしたりと、コードを詰める方向で書きました。これを以下のように書けば少し親切かなと思います。

javascript

1numDiv.textContent = parseInt(numDiv.textContent) + (btnIndex % 2 === 0 ? 1 : -1);

コメントへの回答は以上です。

投稿2019/06/15 05:17

編集2019/06/16 08:22
jun68ykt

総合スコア9058

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

T.Takeda

2019/06/15 22:52

ご回答ありがとうございます。 「ボタンのインデクスを使う例」について、後学のために2点質問させてください。 ・`(+numDiv.textContent)`の書き方は初めてみたのですが、もし特別な表記方法なのであれば名前を教えていただけますか。自身で調べてみたいと思います。 なお、試しに`numDiv.textContent`とに変えて実行してみたところ、ボタンを押すたびにnumDiv内に"1"というテキストが追加されました。 ・条件 (三項) 演算子の記載についてですが、`btnIndex % 2 ? -1 : 1`は奇数がtrueで偶数がfalseということでしょうか。感覚的に2で割り切れればtrueに感じてしまうのですが。。。 初歩的な質問で申し訳ございませんが、ご教示いただけると助かります。 よろしくお願いします。
jun68ykt

2019/06/16 04:59

どうしたしまして。 > 後学のために2点質問させてください。 について、回答のほうに追記しました。ご不明な点があれば、またお知らせください。
T.Takeda

2019/06/16 05:07

丁寧にご回答いただきありがとうございます! 非常にスッキリ致しました。 もう一方の『ボタンのインデクスを使わない例』についても試行錯誤しながら勉強の参考にさせていただきたいと思います。 ありがとうございました。
jun68ykt

2019/06/16 05:11

どういたしまして。解決されたようでよかったです ????
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問