【JavaScript】デリゲートを理解したい
解決済
回答 2
投稿
- 評価
- クリップ 0
- VIEW 3,398
現在JavaScriptの実装をしているのですが、
運用上HTML上でonClick属性を設定しているところを、デリゲートさせて各場所で呼び出すようにしなければなりません。
ただデリゲートは初めて聞いた言葉で調べているのですがいまいち理解できていません。
以下のサイトを拝見しました。
http://blog.webcreativepark.net/2013/12/01-215447.html
http://blog.jnito.com/entry/20110706/1309901221
「メソッドを変数のようにして使うもの」や
「先祖要素にクリックイベントハンドラを登録することで、パブリングの防ぎ、負荷を少なくする方法」
というイメージを持ちました。
しかし、実際に「『デリゲートさせて』各場所で呼び出す」というのはどういうところにポイントを置いて書いたらいいのかがわかりません。
先祖要素にクリックイベントハンドラを登録して、実行したい要素を引数に入れるようにすればいいのか、
あるいはカプセル化?変数のようにメソッドを定義した書き方をすればいいのか、など推測を立てているのですが、まだ掴みきれていません。
もしお答えいただける方がいれば教えていただけると助かります。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+2
個人的にはデリゲートの概念は理解しなくても問題ないと考えています。
jQuery#on
と DOM Events のイベントバブリングだけを理解すれば十分に事足ります。
<div id="parent">
parent
<p id="child">child</p>
</div>
<script type="text/javascript">
'use stirct';
jQuery('#parent').on('click', '#child', function (event) {
console.log('jQuery: ' + this.id); // "jQuery: child"
console.log('jQuery: ' + event.currentTarget.id); // "jQuery: child"
});
document.getElementById('parent').addEventListener('click', function handleClick (event) {
var target = event.target,
id = target.id;
while (id !== 'parent' && id !== 'child') {
target = target.parentNode;
id = target.id
}
if (id !== 'child') {
return;
}
console.log('DOM: ' + target.id); // "DOM: child"
console.log('DOM: ' + this.id); // "DOM: parent"
console.log('DOM: ' + event.currentTarget.id); // "DOM: parent"
}, false);
</script>
- イベント定義しているのは
#parent
なので#child
は動的に削除→生成し直してもイベントを再定義する必要はありません - イベント定義しているのは
#parent
ですが、イベントハンドラ関数内では#child
にイベント定義しているかのように振る舞います(this
値やevent.currentTarget
を書き換えます)
ちなみに、jQuery#on(events, handler)
はイベントバブリングを利用している為、バブリングしないイベントタイプには適用できません。
jQuery はキャプチャリングフェーズに対応していない為、上位ノードで監視可能なイベントタイプに制限があります。
Re: k499778 さん
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+2
delegateは「委譲」という意味で使われています。
「html上、もしくはイベントハンドラ上に処理を書かず、一定のオブジェクトに集約せよ」という指示ではないでしょうか?
例えば、
<button onclick="javascript:alert('委譲を全く使わないパターン');">Click me</button>
となっているところを
<button class="awesome-button">Click me</button>
$(function(){
$('.awesome-button').click(function(){
alert('clicked!');
});
});
と書くことができます。HTML上にjavascriptコードを書かず、javascriptの処理はすべてjs内に書かれているので委譲を使わない場合よりも保守性があがります。
さらに、alert('clicked!')という処理を使いまわしたいならば
<button class="awesome-button">Click me</button>
<button class="newly-added-button">Click me</button>
$(function(){
$('.awesome-button').click(function(){
AlertUtil.doAlert('clicked!');
});
$('.newly-added-button').click(function(){
AlertUtil.doAlert('This is New Button!');
});
});
var AlertUtil={
doAlert:function(msg){
alert(msg);
}
}
と掛けます。この場合、処理を行うのはAlertUtilであり、HTMLとイベント部分の処理は必要な引数だけを渡して処理をAlertUtilに委譲しています。
適切に委譲を使うことで、コードの保守性と再利用性を高めることができます。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.38%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2016/06/01 00:11
>イベント定義しているのは #parent なので #child は動的に削除→生成し直してもイベントを再定義する必要はありません
なるほど。よくイベントを再定義しているのでこの書き方を使えばそれを減らせるかもしれませんね。
イベントバブリングだけを理解すればいいんですね。
ちなみに少し迷うのが「先祖素をどこまで見ればいいか」ということです。
liタグをクリックした時ulタグを超えて、bodyタグとかhtmlタグとかもパブリングしないかなと思い、そこにイベントを設定する必要はないのか、などどの先祖要素にイベントハンドラを設定すればいいのかわからなくなってしまうのです。
もしその疑問を解決する考え方があるのであれば教えていただきたいです。
2016/06/01 00:41
ルートノードとは古くは document ですが、現在は window ですね。
2016/06/01 05:55 編集
となると
>jQuery('#parent').on('click', '#child', function (event) {
の「jQuery('#parent')」の部分は
ルートノードにする必要はないのかな?
という疑問を持ちました。
ご提示下さったコードは先祖要素がparentに当たるためいいと思うのですが、普段コーディングの際はルートノードがdocumentに当たるため、セレクタ部分をどうすればいいのか迷ってしまうのです。
もしその疑問を解決いただけるようであればお答えいただけると嬉しいです。
2016/06/01 11:00 編集
jQuery(document.body).on('click', '#parent', handleClick); // 2番目
jQuery('#paremt').on('click', '#child', handleClick); // 1番目
↓
jQuery(document).on('click', '#parent', handleClick); // 1番目
jQuery(document).on('click', '#child', handleClick); // 2番目
バブリングは子要素から親要素へ順番に発火する為、「#child -> #parent -> document.body -> document.documentElement -> document -> window」の順に発火するわけですが、常に document を指定すると入力順で発火します。
http://www2u.biglobe.ne.jp/~oz-07ams/2003/Events3/xml-source-20031107-ja.xml#Events-flow
ちなみに、document を指定すると DOMContentLoaded を待たなくていい利点はあります。
2016/06/01 12:16
documentにしてもいいが、順序制御が面倒になるのですね。ただメリットもあるが。
スッキリしました。
わからないところは自分で調べて理解を深めます。
長らく相談に乗って頂きありがとうございました。