一、は何ですか#
イベントデリゲートとは、要素のイベント(click
、keydown
など)を別の要素に委任することを指します。
前述のように、イベントフローはキャプチャフェーズ→ターゲットフェーズ→バブリングフェーズを経由しますが、イベントデリゲートはバブリングフェーズで完了します。
イベントデリゲートは、1 つまたは複数の要素のイベントをその親要素またはより外側の要素に委任します。実際にイベントをバインドするのは外側の要素であり、ターゲット要素ではありません。
イベントがターゲット要素に到達すると、イベントバブリングメカニズムによって外側の要素のバインドされたイベントがトリガーされ、外側の要素で関数が実行されます。
以下に例を示します:
例えば、寮の学生が同時に荷物を受け取った場合、一つずつ受け取るのは面倒です。
より効率的な方法は、この作業を寮長に委任し、一人がすべての荷物を受け取り、それから受取人ごとに各学生に配布することです。
ここで、荷物を受け取ることはイベントであり、各学生はイベントに応答する必要がある DOM
要素を指します。そして、一斉に荷物を受け取る寮長は代理要素です。
したがって、実際にイベントをバインドするのはこの要素であり、イベントの実行中には、現在のイベントが代理要素のどの要素に一致するかを判断する必要があります。
二、応用シナリオ#
リストがあり、そのリストには多くのリストアイテムが含まれており、リストアイテムをクリックしたときにイベントに応答する必要がある場合を考えます。
<ul id="list">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
......
<li>item n</li>
</ul>
各リストアイテムに個別に関数をバインドすると、メモリ消費量が非常に大きくなります。
// ターゲット要素を取得
const lis = document.getElementsByTagName("li")
// ループしてイベントをバインド
for (let i = 0; i < lis.length; i++) {
lis[i].onclick = function(e){
console.log(e.target.innerHTML)
}
}
この場合、イベントデリゲートを使用して、クリックイベントを親要素の ul
にバインドし、イベントを実行するときにターゲット要素を一致させることができます。
// 親要素にイベントをバインド
document.getElementById('list').addEventListener('click', function (e) {
// 互換性の処理
var event = e || window.event;
var target = event.target || event.srcElement;
// ターゲット要素と一致するかどうかを判断
if (target.nodeName.toLocaleLowerCase === 'li') {
console.log('the content is: ', target.innerHTML);
}
});
また、上記のリストアイテムが多くない場合でも、各リストアイテムにイベントをバインドしている場合、ユーザーがリストアイテムの要素を動的に追加または削除できる場合、新しい要素に対してイベントを再度バインドし、削除する要素のイベントを解除する必要があります。
イベントデリゲートを使用すると、イベントは親要素にバインドされるため、ターゲット要素の追加や削除とは関係がありません。ターゲット要素が実際に実行されるイベント関数の中で一致することになります。
例を示します:
以下のhtml
構造では、input
をクリックすると要素が動的に追加されます。
<input type="button" name="" id="btn" value="追加" />
<ul id="ul1">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
<li>item 4</li>
</ul>
イベントデリゲートを使用する
const oBtn = document.getElementById("btn");
const oUl = document.getElementById("ul1");
const num = 4;
// イベントデリゲート、追加された子要素にもイベントがあります
oUl.onclick = function (ev) {
ev = ev || window.event;
const target = ev.target || ev.srcElement;
if (target.nodeName.toLowerCase() == 'li') {
console.log('the content is: ', target.innerHTML);
}
};
// 新しいノードを追加
oBtn.onclick = function () {
num++;
const oLi = document.createElement('li');
oLi.innerHTML = `item ${num}`;
oUl.appendChild(oLi);
};
イベントデリゲートを使用すると、動的にイベントをバインドする場合に重複する作業を大幅に削減できることがわかります。
三、まとめ#
イベントデリゲートに適したイベントは、click
、mousedown
、mouseup
、keydown
、keyup
、keypress
です。
上記の応用シナリオからわかるように、イベントデリゲートの利点は 2 つあります:
- ページ全体のメモリ使用量を減らし、全体的なパフォーマンスを向上させることができます。
- 動的にバインドすることができ、重複作業を減らすことができます。
ただし、イベントデリゲートには制限もあります:
-
focus
、blur
などのイベントにはイベントバブリングメカニズムがないため、デリゲートバインドすることはできません。 -
mousemove
、mouseout
などのイベントはイベントバブリングがありますが、位置を計算して位置を特定する必要があるため、パフォーマンスの消費が高く、イベントデリゲートには適していません。
すべてのイベントをイベントデリゲートに使用すると、イベントの誤判定が発生する可能性があります。つまり、本来トリガーされるべきでないイベントがイベントにバインドされてしまうことがあります。