AngularJSチュートリアル:カスタムディレクティブの謎を解く
公開: 2022-03-11フルスタック言語としてのJavaScriptの急速な成長に伴い、Webブラウザーがデータバインディング、データビューの管理、データの変換、その他の多くのサービスなどのUI処理を処理できるようにするフレームワークを利用するアプリケーションが増えています。 最も有能で拡張可能で人気のあるフレームワークの1つはAngularJSであり、AngularJSフレームワークの最も有用なコンポーネントの1つはディレクティブと呼ばれるものです。 AngularJSは多くの便利なディレクティブを提供し、さらに重要なことに、カスタムディレクティブを作成するための豊富なフレームワークを提供します。
ディレクティブとは何ですか? 簡単に言うと、ディレクティブは、HTMLDOM要素を操作して動作を追加するJavaScript関数です。 ディレクティブは、非常に単純な場合もあれば、非常に複雑な場合もあります。 したがって、それらを操作する多くのオプションと機能をしっかりと把握することが重要です。
このチュートリアルでは、ディレクティブとして実行される4つの関数が作成され、DOMに適用され、例が提供されます。 この投稿は、AngularJSとカスタムディレクティブにある程度精通していることを前提としています。 Angularを初めて使用する場合は、最初のAngularJSアプリの作成に関するチュートリアルをお楽しみください。
AngularJSディレクティブライフサイクルの4つの機能
構成できるオプションは多数あり、それらのオプションが互いにどのように関連しているかが重要です。 各ディレクティブは、AngularJSがDOMをコンパイルしてリンクするときに、ライフサイクルに似たものを実行します。 ディレクティブのライフサイクルは、ページがレンダリングされる前に、AngularJSブートストラッププロセス内で開始および終了します。 ディレクティブのライフサイクルには、定義されている場合に実行できる4つの異なる関数があります。 それぞれにより、開発者はライフサイクルのさまざまな時点でディレクティブを制御およびカスタマイズできます。
4つの機能は、コンパイル、コントローラー、プリリンク、ポストリンクです。
コンパイル機能を使用すると、ディレクティブは、コンパイルおよびリンクされる前にDOMを操作できるため、ディレクティブの追加/削除/変更、および他のDOM要素の追加/削除/変更が可能になります。
コントローラ機能により、ディレクティブ通信が容易になります。 兄弟および子ディレクティブは、兄弟および親のコントローラーに情報の伝達を要求できます。
プレリンク関数を使用すると、ポストリンクプロセスを開始する前にプライベート$scopeを操作できます。
ポストリンクメソッドは、ディレクティブの主要な主力メソッドです。
ディレクティブでは、コンパイル後のDOM操作が行われ、イベントハンドラーが構成され、ウォッチなども構成されます。 ディレクティブの宣言では、4つの関数がこのように定義されています。
.directive("directiveName",function () { return { controller: function() { // controller code here... }, compile: { // compile code here... return { pre: function() { // pre-link code here... }, post: function() { // post-link code here... } }; } } })
通常、すべての機能が必要なわけではありません。 ほとんどの場合、開発者は以下のパターンに従ってコントローラーとポストリンク関数を作成するだけです。
.directive("directiveName",function () { return { controller: function() { // controller code here... }, link: function() { // post-link code here... } } })
この構成では、リンクはリンク後の機能を指します。
すべての関数または一部の関数が定義されているかどうかに関係なく、それらの実行順序、特にAngularJSアプリケーションの残りの部分と比較した実行は重要です。
他のディレクティブと比較したAngularJSディレクティブ関数の実行
HTMLフラグメントに適用されたディレクティブparentDir 、 childDir 、およびgrandChildDirを持つ次のHTMLスニペットについて考えてみます。
<div parentDir> <div childDir> <div grandChildDir> </div> </div> </div>
ディレクティブ内の関数の実行順序、および他のディレクティブとの相対的な順序は次のとおりです。
- コンパイルフェーズ
- コンパイル関数:parentDir
- コンパイル関数:childDir
- コンパイル関数:grandChildDir
- コントローラーとプレリンクフェーズ
- コントローラー関数:parentDir
- プレリンク関数:parentDir
- コントローラー関数:childDir
- プレリンク関数:childDir
- コントローラー関数:grandChildDir
- プレリンク関数:grandChildDir
- リンク後のフェーズ
- ポストリンク関数:grandChildDir
- ポストリンク関数:childDir
- ポストリンク関数:parentDir
AngularJSディレクティブ関数の説明:詳細
コンパイルフェーズが最初に発生します。 基本的に、コンパイルフェーズではイベントリスナーをDOM要素にアタッチします。 たとえば、特定のDOM要素が$ scopeプロパティにバインドされている場合、 $scopeプロパティの値で更新できるようにするイベントリスナーがDOM要素に適用されます。 コンパイルのプロセスは、AngularJSアプリケーションがブートストラップされたルートDOM要素から始まり、深さ優先トラバーサルを使用してDOMのブランチをトラバースし、最初に親をコンパイルし、次にその子をリーフノードまでコンパイルします。
コンパイルが完了すると、ディレクティブをDOMに追加したり、DOMから削除したりすることはできなくなります(ただし、コンパイルサービスを直接使用することでこれを回避できます。次のフェーズは、すべてのディレクティブのコントローラーとプリリンク関数の呼び出しです。コントローラーの場合が呼び出されると、 $ scopeが使用可能になり、使用できます。コントローラーに挿入された$要素には、コンパイルされたテンプレートが含まれますが、トランスクルージョンされた子コンテンツは含まれません(トランスクルージョンされたコンテンツは、ディレクティブが含まれる開始HTMLタグと終了HTMLタグの間のコンテンツです。定義上、MVCパターンのコントローラーは、モデルをビューに渡し、イベントを処理するための関数を定義するだけです。したがって、ディレクティブのコントローラーは、2つの理由でディレクティブのDOMを変更しないでください。コントローラー、およびトランスクルージョンされた子コンテンツはDOMに追加されていません。では、コントローラーは$ scopeを変更する以外に何をしますか?コントローラーは、子ディレクティブがwiと通信できるようにします。 親ディレクティブ。 コントローラ関数自体は、子ディレクティブが要求した場合に子ディレクティブのリンク後関数に渡されるコントローラオブジェクトと見なす必要があります。 したがって、コントローラーは通常、兄弟および子ディレクティブで使用できるプロパティとメソッドを持つオブジェクトを作成することにより、ディレクティブ通信を容易にするために使用されます。 親ディレクティブは、子ディレクティブがそのコントローラーを要求できるかどうかを判断できないため、このメソッドのコードを、子ディレクティブで安全に使用できる関数とプロパティに制限することをお勧めします。

コントローラ機能の後、プリリンク機能が実行されます。 プレリンク機能は多くの人にとって不思議です。 インターネットや本で多くのドキュメントを読んだ場合、この関数はまれな状況でのみ使用され、人々はほとんどそれを必要としないだろうと人々は書いています。 それらの同じ説明は、それが使用される可能性がある状況の例を与えることができません。
プレリンク機能は実際にはまったく複雑ではありません。 まず、AngularJSのソースコードを確認すると、リンク前関数の優れた例が見つかります。ディレクティブng-initがそれを使用します。 なんで? これは、 $scopeを含むプライベートコードを実行するための優れた方法です。 兄弟および子ディレクティブでは呼び出せないコード。 コントローラ関数とは異なり、プリリンク関数はディレクティブに渡されません。 したがって、ディレクティブの$scopeを変更するコードを実行するために使用できます。 ディレクティブng-initはまさにこれを行います。 ng-initのpre-link関数が実行されると、ディレクティブの$scopeに対してディレクティブに渡されたJavaScriptが実行されるだけです。 実行の結果は、コントローラー、リンク前およびリンク後の関数の実行中に$ scopeの子ディレクティブへのプロトタイプの継承を通じて利用できますが、親のpre-のコードを再実行するためにこれらの子ディレクティブにアクセスすることはできません。リンク機能。 また、ディレクティブは、プライベートにしておきたい$scopeに関連しない他のコードを実行する必要がある場合があります。
経験豊富なAngularJS開発者の中には、このプライベートコードをコントローラーに配置しても、子ディレクティブによって呼び出されない可能性があると言う人もいます。 ディレクティブがそれをコーディングした元の開発者によってのみ使用される場合、その引数は当てはまりますが、ディレクティブが他の開発者によって配布および再利用される場合、プリリンク関数にプライベートコードをカプセル化することは非常に有益です。 開発者は、ディレクティブが時間の経過とともにどのように再利用されるかを知らないため、プライベートコードを子ディレクティブによって実行されないように保護することは、ディレクティブコードをカプセル化するための優れたアプローチです。 コントローラ関数にディレクティブ通信パブリックコードを配置し、プリリンク関数にプライベートコードを配置することをお勧めします。 コントローラと同様に、子ディレクティブのコンテンツはまだリンクされていないため、プレリンクはDOM操作を実行したりトランスクルージョン関数を実行したりしないでください。
ディレクティブごとに、そのコントローラーとプレリンク関数は、その子ディレクティブのコントローラーとプレリンク関数の前に実行されます。 すべてのディレクティブのコントローラーとプレリンクフェーズが完了すると、AngularJSはリンクフェーズを開始し、各ディレクティブのポストリンク機能を実行します。 リンクフェーズは、コンパイル、コントローラー、およびリンク前の実行フローとは逆に実行され、リーフDOMノードから開始して、ルートDOMノードまで進みます。 リンク後のDOMトラバーサルは、ほとんどが深さ優先のパスをたどります。 各子ディレクティブがリンクされると、そのpost-link関数が実行されます。
ポストリンク関数は、カスタムAngularJSディレクティブで最も一般的に実装される関数です。 この関数では、ほとんどすべての合理的なことが実行できます。 DOMの操作(それ自体と子要素のみ)、 $ scopeの使用、親ディレクティブのコントローラーオブジェクトの使用、トランスクルージョン関数の実行などが可能です。ただし、いくつかの制限があります。 新しいディレクティブはコンパイルされないため、DOMに追加することはできません。 さらに、すべてのDOM操作はDOM関数を使用して実行する必要があります。 DOM要素でhtml関数を呼び出し、新しいHTMLを渡すだけで、コンパイルプロセス中に追加されたすべてのイベントハンドラーが削除されます。 たとえば、これらは期待どおりに機能しません。
element.html(element.html());
また
element.html(element.html() + "<div>new content</div>");
コードによってHTMLが変更されることはありませんが、DOM要素の文字列バージョンを再割り当てすると、コンパイルプロセス中に作成されたすべてのイベントハンドラーが削除されます。 通常、リンク後関数は、イベントハンドラー、 $ watchesおよび$observeを接続するために使用されます。
すべてのリンク後関数が実行されると、コンパイルおよびリンクされたDOM構造に$ scopeが適用され、AngularJSページが有効になります。
指令機能チャート
これは、各関数の目的、実行時に使用できるもの、および各関数を適切に使用するためのベストプラクティスをリストしたチャートです。
実行 注文 | 指令 関数 | DOM | トランスクルージョン | $ scope | 呼び出し可能 子供によって |
---|---|---|---|---|---|
1 | コンパイル | DOMはコンパイルされていませんが、テンプレートがDOM要素のコンテンツ領域にロードされています。 ディレクティブは追加および削除できます。 DOMは、DOM関数とHTML文字列置換の両方で操作できます。 | トランスクルージョン関数は使用可能ですが、非推奨であり、呼び出すべきではありません。 | 利用不可。 | 子要素から関数を呼び出すことはできません。 |
2 | コントローラ | コンパイルされたDOM要素は使用可能ですが、変更しないでください。 トランスクルージョンされた子コンテンツはDOM要素に追加されていません。 これはコントローラーであり、トランスクルージョンされた子コンテンツはまだリンクされていないため、DOMの変更は発生しません。 | トランスクルージョン関数は使用可能ですが、呼び出さないでください。 | $ scopeが利用可能であり、使用できます。 関数パラメーターは、 $injectorサービスを使用して注入されます。 | 関数は子ディレクティブリンク関数に渡され、それらから呼び出すことができます。 |
3 | プレリンク | コンパイルされたDOM要素は使用可能ですが、子ディレクティブDOM要素はまだリンクされていないため、変更しないでください。 | トランスクルージョン関数は使用可能ですが、呼び出さないでください。 | $ scopeが利用可能であり、変更できます。 | 関数は子ディレクティブでは呼び出せません。 ただし、親ディレクティブのコントローラーを呼び出す場合があります。 |
4 | ポストリンク | コンパイルされたDOM要素と子ディレクティブDOM要素が利用可能です。 DOMはDOM関数のみ(HTML置換なし)で変更でき、コンパイルを必要としないコンテンツのみを追加できます。 ディレクティブの追加/削除は許可されていません。 | トランスクルージョン関数が利用可能であり、呼び出すことができます。 | $ scopeが利用可能であり、使用できます。 | ディレクティブの子からは呼び出せませんが、親ディレクティブのコントローラーを呼び出すことができます。 |
概要
AngularJSディレクティブに関するこのチュートリアルでは、コンパイル、コントローラー、プレリンク、ポストリンクの4つのディレクティブ関数のそれぞれの目的、実行順序、全体的な機能と使用法について学習しました。 4つの関数のうち、コントローラーとポストリンクが最も一般的に使用されますが、DOMをより細かく制御する必要がある、またはプライベートスコープの実行環境が必要な、より複雑なディレクティブの場合は、コンパイル関数とプリリンク関数を利用できます。