JavaScriptでの新しい要素へのイベントハンドラの追加
ここにリスト ul とボタンがあるとします:
<ul>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
</ul>
<button>add</button>
対応する変数に要素を取得しましょう:
let button = document.querySelector('button');
let list = document.querySelector('ul');
let items = list.querySelectorAll('li');
任意の li をクリックすると、
その末尾に感嘆符が追加されるようにしましょう:
for (let item of items) {
item.addEventListener('click', function() {
this.textContent = this.textContent + '!';
});
}
次に、ボタンを押すとリストの末尾に新しい
li が追加されるようにしましょう:
button.addEventListener('click', function() {
let item = document.createElement('li');
item.textContent = 'item';
list.appendChild(item);
});
しかし、ここで問題が発生します: 新しく追加された
li をクリックしても、末尾に感嘆符が追加されません。
なぜなら、クリックハンドラは最初から存在していた
li にのみ追加されており、新しい要素には追加されていない
からです。
この問題を修正するために、新しい li に
クリックハンドラを追加しましょう:
button.addEventListener('click', function() {
let item = document.createElement('li');
item.textContent = 'item';
item.addEventListener('click', function() { // クリックハンドラ
this.textContent = this.textContent + '!';
});
list.appendChild(item);
});
しかし、これではハンドラ関数のコードが
2か所(最初から存在する li 用と新しい要素用)で
重複しています。これを修正するため、コードを別の関数に
抽出しましょう:
function handler() {
this.textContent = this.textContent + '!';
}
この関数を使用して、コードの重複を回避しましょう:
for (let item of items) {
item.addEventListener('click', handler);
}
button.addEventListener('click', function() {
let item = document.createElement('li');
item.textContent = 'item';
item.addEventListener('click', handler);
list.appendChild(item);
});
問題は概ね解決し、ハンドラ関数のコードの重複は避けられました。
しかし、イベントハンドラの追加は依然として2か所
(既存の li のためのループ内と、ボタンクリック時)で
行う必要があります。次のレッスンでは、この不便さを
解消する方法について検討します。