通常、ng で命令を使用する場合、最も一般的に使用されるリンク関数は link 属性です。次の記事では、complie、pre-link、post-link の使用法と違いについて説明します。
angularjs のディレクティブは非常に魅力的で、非常にセマンティックで再利用性の高いコンポーネントを作成できます。
インターネット上には、使用方法に関する記事や関連書籍が数多くありますが、コンパイルとリンクの違い、ましてやプレリンクとポストリンクの違いについてはほとんど紹介されていません。
ほとんどのチュートリアルでは、単に ng の内部でコンパイルが使用されると述べており、ほとんどの命令例ではリンク属性のみを使用することをお勧めします。
これは非常に残念なことです。これらの関数の違いを正しく理解することで、ng の内部動作メカニズムの理解が深まり、より良いカスタム命令の開発に役立つからです。
従って、次のコンテンツを段階的に読んで、これらの関数が何であるか、いつ使用する必要があるかを理解してください
この記事は、ディレクティブについてすでにある程度理解していることを前提としています。まだ理解していない場合は、この記事ディレクティブに関する AngularJS 開発者ガイドのセクションを読むことを強くお勧めします。
NG時の指示の処理方法
分析を始める前に、まず ng で命令がどのように処理されるかを見てみましょう。
ブラウザはページをレンダリングするときに、基本的に HTML タグを読み取り、dom ノードを作成し、dom ツリーの作成後にイベントをブロードキャストします。
script タグを使用してページに ng アプリケーション コードをロードすると、ng は上記の dom 完了イベントをリッスンし、ng-app 属性を持つ要素を探します。
そのような要素が見つかった場合、ng はその要素の開始点から dom の処理を開始します。そのため、html 要素に ng-app を追加すると、ng は html 要素から dom の処理を開始します。
この開始点から、ng はアプリケーションで定義された命令ルールに準拠するすべてのサブ要素の再帰的な検索を開始します。
ng が実際に命令を処理する方法は、オブジェクトの定義時のオブジェクト属性によって決まります。コンパイル関数またはリンク関数を定義したり、リンクの代わりにプレリンク関数やポストリンク関数を使用したりできます。
では、これらの関数の違いは何ですか?また、いつ使用する必要があるのでしょうか?
これらの質問については、私に従ってステップバイステップで謎に答えてください
コードの一部
これらの関数の違いを説明するために、以下にシンプルでわかりやすい例を使用します
1. ご質問がございましたら、お気軽にコメントを追加してください。
次の HTML タグ コードを見てください
function createDirective(name){
return function(){
戻り値 {
制限: 'E'、
コンパイル: function(tElem, tAttrs){
console.log(名前 ': コンパイル');
戻り値 {
pre: function(scope, iElem, iAttrs){
console.log(名前 ': プレリンク');
}、
post: function(scope, iElem, iAttrs){
console.log(名前 ': 投稿リンク');
}
}
}
}
}
}
app.directive('levelOne', createDirective('levelOne'));
app.directive('levelTwo', createDirective('levelTwo'));
app.directive('levelThree', createDirective('levelThree'));
結果非常に简单: 3 つの適合命令を処理し、および各命令すべてが独自のコンパイル、プレリンク、ポストリンク関数、每个関数都市在制御台里打印一行东西来标识自己.
この例は、命令の処理時に内部の流れを理解することができます
代码输出
以下は制御台の出力結果の図です
如果自己想试下この例の话、请点击このplnkr、その後制御台查看結果。
分析代
最初に注意すべきは、これらの関数の使用順序です:
// リンク前フェーズ
// levelOne: プレリンク関数が呼び出されます
// levelTwo: プレリンク関数が呼び出されます
// levelThree: プレリンク関数が呼び出されます
// リンク後のフェーズ (順序が逆であることに注意してください)
// levelThree: ポストリンク関数が呼び出されます
// levelTwo: ポストリンク関数が呼び出されます
// levelOne: ポストリンク関数が呼び出されます
この例の明確な表示は、リンクの前にすべての命令があり、その後リンクがプレリンクとポストリンクのセグメントに分かれています。
注意してください、コンパイルとリンク前の実行順序は逐次実行されますが、リンク後の実行はその逆です。
上記で異なる段階が示されていますが、コンパイルとプリリンクにはどのような領域があり、すべて同じ実行順序であり、どのような分割が必要なのか?
ドム
より深い点を達成するために、私は一個の修正を行った上で、各関数の印刷パラメータ列表内の要素の量を確認します。
function createDirective(name){
return function(){
戻り値 {
制限: 'E'、
コンパイル: function(tElem, tAttrs){
console.log(name ':compile => ' tElem.html());
戻り値 {
pre: function(scope, iElem, iAttrs){
console.log(name ': pre link => ' iElem.html());
}、
post: function(scope, iElem, iAttrs){
console.log(name ': 投稿リンク => ' iElem.html());
}
}
}
}
}
}
app.directive('levelOne', createDirective('levelOne'));
app.directive('levelTwo', createDirective('levelTwo'));
app.directive('levelThree', createDirective('levelThree'));
console.log の出力に注目してください。元の HTML マークアップの出力以外には、基本的には変更はありません。
これにより、これらの関数のコンテキストについての理解が深まるはずです。
コードを再度実行して確認してください
出力
以下はコンソール出力のスクリーンショットです
それでも自分で実行して効果を確認したい場合は、この plnkr、 をクリックして、コンソールで出力結果を表示できます
。観察
dom を出力した結果、いくつかの興味深いことがわかります。dom の内容は、コンパイル関数とプリリンク関数で異なります。
それで、何が起こったのですか?
コンパイル
ng は dom の構築が完了したことが分かると dom の処理を開始することはすでにわかっています。
したがって、ng が dom を横断しているときに、レベル 1 要素に遭遇し、その定義から必要な関数をいくつか実行する必要があることを学習します
コンパイル関数はレベル 1 ディレクティブのコマンド オブジェクトで定義されているため、呼び出され、要素オブジェクトがパラメータとして渡されます
注意深く見ると、ブラウザがこの要素オブジェクトを作成するとき、それはまだ元の HTML マークアップであることがわかります
1. ng では、通常、テンプレート要素を識別するために元の dom が使用されるため、コンパイル関数のパラメーターを定義するときに、この変数はテンプレート要素を指します。
levelone ディレクティブのコンパイル関数が実行されると、ng はその DOM ノードを再帰的に深く走査し、レベル 2 とレベル 3 でこれらの操作を繰り返します。
ポストリンク
プレリンク関数について説明する前に、ポストリンク関数を見てみましょう。2. 命令を定義するときにリンク関数を 1 つだけ使用する場合、ng はこの関数をポストリンクとして扱うため、最初にこの関数について説明する必要があります
ng はすべての DOM を走査し、すべてのコンパイル関数を実行した後、関連するポストリンク関数を逆に呼び出します。
DOM はリバースしてポストリンク関数の実行を開始します。したがって、このリバース呼び出しは以前は少し奇妙に思えましたが、実際には完全に理にかなっています。
サブコマンドを含むコマンド ポストリンクを実行する場合、リバース ポストリンク ルールにより、そのサブコマンドのポストリンクがすでに実行されていることを確認できます。
したがって、レベル 1 命令のポストリンク関数を実行するときに、レベル 2 とレベル 3 のポストリンクが実際に実行されたことを確認できます。
これが、人々がポストリンクがビジネス ロジックを記述するための最も安全な、またはデフォルトの場所であると考える理由です。
しかし、ここの要素がコンパイルの要素と異なるのはなぜですか?
ng が命令のコンパイル関数を呼び出すと、テンプレート要素の要素インスタンス オブジェクトが作成され、それにスコープ オブジェクトが提供されます。このスコープは新しいインスタンスであるか、すでに存在している可能性があります。サブスコープは独立したスコープである場合もありますが、これはすべて命令定義オブジェクト
のスコープ属性値に依存します。リンクが行われるとき、このインスタンス要素とスコープ オブジェクトはすでに利用可能であり、ng によってポストリンク関数のパラメーター リストにパラメーターとして渡されます。
1. 私は常に iElem 名を使用してリンク関数のパラメーターを定義し、要素インスタンス
を指します。したがって、ポストリンク (プレリンク) 関数の要素パラメーター オブジェクトは、テンプレート要素ではなく要素インスタンスです。
つまり、上記の例の出力は異なります
プレリンクポストリンク関数を作成する場合、ポストリンク関数の実行時に、そのすべての子命令のポストリンク関数がすでに実行されていることを確認できます。
ほとんどの場合、この方が効率的に実行できるため、通常はこれを使用して命令コードを記述します。
ただし、ng は、すべてのサブ命令のポストリンク関数が実行される前に他のコードが確実に実行されるようにする、プレリンク関数という追加のフック メカニズムを提供します。
この文は繰り返し検討する価値がありますプレリンク関数は、要素インスタンスのポストリンクとそのすべてのサブ命令が実行される前に実行されることが保証されています。
したがって、ポストリンク関数を逆に実行するのは理にかなっていて、それ自体がプレリンク関数の本来の順次実行です
これは、プレリンク関数がそのすべてのサブ命令のプレリンク関数よりも前に実行されることも意味します。したがって、完全な理由は次のとおりです。
要素の pre-link 関数は、そのすべてのサブコマンドの post-link および pre-link が実行される前に実行されることが保証されています。
を参照してください。
レビュー
上記の元の出力を振り返ると、何が起こったのかを明確に認識できます。
// コンパイルフェーズ
// levelOne: 元の DOM でコンパイル関数が呼び出されます
// levelTwo: 元の DOM でコンパイル関数が呼び出されます
// levelThree: 元の DOM でコンパイル関数が呼び出されます
// ここの時点で、要素はインスタンス化されており、
// スコープにバインドされています
// (例: NG-REPEAT には複数のインスタンスがあります)
// リンク前フェーズ
// levelOne: 要素インスタンスでプレリンク関数が呼び出されます
// levelTwo: 要素インスタンスでプレリンク関数が呼び出されます
// levelThree: 要素インスタンスでプレリンク関数が呼び出されます
// リンク後のフェーズ (順序が逆であることに注意してください)
// levelThree: ポストリンク関数が要素インスタンスで呼び出されます
// levelTwo: post link 関数が要素インスタンスで呼び出されます
// levelOne: ポストリンク関数が要素インスタンスで呼び出されます
概要
上の分析を振り返って、これらの関数の領域と使用状況を以下に説明します:
コンパイル関数
compile 関数を使用すると、元の dom 例およびスコープの例を作成する前に、元の dom (テンプレート要素) を変更できます。
複数の要素のインスタンスを生成する必要がある場合、テンプレート要素が 1 つだけある場合に使用できます。ng-repeat が最適な例であり、コンパイル関数の段階で変更のオリジナルの dom が複数生成されます。要素の例をそれぞれ生成します。コンパイルだけが 1 回実行されるため、複数の要素の例を生成する必要がある場合は、性能を向上させることができます。
テンプレート要素および関連するプロパティはコンパイル関数のパラメーターとして使用されており、現時点ではスコープは使用できません:
次は関数数样子:
// ...
};
プリリンク関数
pre-link 関数を使用すると、完了コンパイル関数を実行した後でいくつかのトラフィックコードを実行できますが、すべての子命令の post-link 関数を実行する前に実行する必要があります。
スコープオブジェクトおよび要素の例は、パラメータの事前リンク関数として行われます:
次は関数数样子:
// ...
};
ポストリンク関数数
ポストリンク関数を使用してトラフィックを実行し、この段階で既に知られているすべての子命令が完了し、プレリンクおよびポストリンク関数も完了します。
これは、最も安全であると認められている、また、認められているセキュリティコードの理由です。
スコープの例および実行要素の例はパラメータ传递给post-link関数:
次は関数数样子:
// ...
};
概要
これで、コンパイル関数、プリリンク関数、ポストリンク関数の違いを明確に理解できるようになりました。
まだ読んでおらず、本格的な NG 開発者である場合は、理解するまでこの記事をもう一度読むことを強くお勧めします
これらの概念を理解することは非常に重要です。これは、NG のネイティブ命令がどのように機能するかを理解するのに役立ち、また、独自のカスタム命令を最適化するのにも役立ちます。
まだご質問がある場合は、下のコメント欄に質問を追加してください
今後、この指令の他の 2 つの問題を分析します。
1. ディレクティブはトランスクルージョン属性をどのように使用しますか?
2. 命令のコントローラー機能はどのように関連していますか?
最後に、この記事に何か間違っている点を見つけた場合は、時間内にコメントを送ってください
ありがとうございます!