265

新しいディレクティブを作成するときに使用するスコープのタイプを決定するのに役立つガイドラインを探しています。理想的には、一連の質問を案内し、正しい答えをポップアウトするフローチャートに似たものが欲しいです。新しいスコープ、新しい子スコープ、または新しい分離スコープはありませんが、それは多すぎることを求めている可能性があります。これが私の現在のガイドラインのセットです:

  • ディレクティブを使用する要素がng-modelを使用する場合は、分離スコープを使用しないでください。「分離スコープで ng-modelを使用できますか?
    」を参照してください。フォーマッタが分離スコープで機能しないのはなぜですか?
  • ディレクティブがスコープ/モデルのプロパティを変更しない場合は、新しいスコープを作成しないでください
  • ディレクティブがDOM要素のセットをカプセル化していて(ドキュメントには「複雑なDOM構造」と記載されています)、ディレクティブが要素として使用される場合、または同じ要素に他のディレクティブがない場合は、スコープの分離が適切に機能するようです。

要素に分離スコープを持つディレクティブを使用すると、同じ要素上の他のすべてのディレクティブが同じ(1つの)分離スコープを使用するように強制されることを知っています。したがって、分離スコープを使用できる場合、これは厳しく制限されませんか?

Angular-UIチームの一部(または多くのディレクティブを作成した他のチーム)が彼らの経験を共有できることを願っています。

「再利用可能なコンポーネントには分離されたスコープを使用する」という単純な回答を追加しないでください。

4

5 に答える 5

291

なんて素晴らしい質問でしょう!他の方の意見も聞きたいのですが、私が使用しているガイドラインを以下に示します。

高高度の前提: スコープは、親コントローラー、ディレクティブ、およびディレクティブ テンプレート間の通信に使用する「接着剤」として使用されます。

親スコープ: scope: false、したがって新しいスコープはまったくありません

私はこれをあまり頻繁に使用しませんが、@MarkRajcok が言ったように、ディレクティブがスコープ変数にアクセスしない場合 (そして明らかに何も設定しない場合)、私に関する限り、これは問題ありません。これは、親ディレクティブのコンテキストでのみ使用され (これには常に例外があります)、テンプレートを持たない子ディレクティブにも役立ちます。基本的に、テンプレートを使用するものはすべてスコープを共有するものではありません。これは、アクセスと操作のためにそのスコープを本質的に公開しているためです (ただし、この規則には例外があると確信しています)。

例として、私は最近、作成中の SVG ライブラリを使用して (静的) ベクター グラフィックを描画するディレクティブを作成しました。2つ$observeの属性 (widthheight) があり、それらを計算に使用しますが、スコープ変数の設定も読み取りも行わず、テンプレートもありません。これは、別のスコープを作成しない場合の適切な使用例です。私たちはそれを必要としないので、なぜ気にするのですか?

しかし、別の SVG ディレクティブでは、使用するデータのセットが必要であり、さらに少量の状態を保存する必要がありました。この場合、親スコープを使用することは無責任です (繰り返しますが、一般的に言えば)。代わりに...

子スコープ: scope: true

子スコープを持つディレクティブはコンテキストを認識し、現在のスコープと対話することを目的としています。

明らかに、isolate スコープに対するこれの主な利点は、ユーザーが必要な属性に対して自由に補間を使用できることです。たとえばclass="item-type-{{item.type}}"、isolate スコープを持つディレクティブを使用すると、デフォルトでは機能しませんが、子スコープを持つディレクティブでは正常に機能します。また、ディレクティブ自体は、親の汚染や損傷を心配することなく、独自のスコープのコンテキストで属性と式を安全に評価できます。

たとえば、ツールチップは追加されるだけのものです。ここで他のディレクティブまたは補間された属性を使用することが予想されるため、isolate スコープは機能しません (デフォルトでは、以下を参照)。ツールチップは単なる拡張機能です。しかし、ツールチップは、サブディレクティブおよび/またはテンプレートで使用するためにスコープにいくつかのものを設定する必要があり、明らかにそれ自体の状態を管理する必要があるため、親スコープを使用するのは実際にはかなり悪いでしょう. 私たちはそれを汚染するか、損傷するかのどちらかであり、どちらもブエノではありません.

私は子スコープを分離スコープや親スコープよりも頻繁に使用していることに気づきました。

スコープを分離: scope: {}

これは再利用可能なコンポーネント用です。:-)

しかし、真剣に、「再利用可能なコンポーネント」を「自己完結型のコンポーネント」と考えています。その意図は、それらを特定の目的に使用することであるため、それらを他のディレクティブと組み合わせたり、他の補間属性を DOM ノードに追加したりすることは、本質的に意味がありません。

より具体的には、このスタンドアロン機能に必要なものはすべて、親スコープのコンテキストで評価される指定された属性を通じて提供されます。それらは、一方向の文字列 ('@')、一方向の式 ('&')、または双方向の変数バインディング ('=') のいずれかです。

自己完結型のコンポーネントでは、それ自体が存在するため、他のディレクティブや属性を適用する必要はありません。そのスタイルは独自のテンプレートによって管理され (必要な場合)、適切なコンテンツをトランスクルードすることができます (必要な場合)。これはスタンドアロンなので、isolate スコープに入れて、「これをいじらないでください。これらのいくつかの属性を介して定義済みの API を提供します」とも言います。

良いベスト プラクティスは、ディレクティブ リンクとコントローラー関数からできるだけ多くのテンプレート ベースのものを除外することです。これにより、もう 1 つの「API のような」構成ポイントが提供されます。ディレクティブのユーザーは、テンプレートを簡単に置き換えることができます。機能はすべて同じままで、その内部 API には一切手を加えていませんが、必要に応じてスタイリングと DOM 実装をいじることができます。ui/bootstrap は、Peter と Pawel が素晴らしいので、これをうまく行う方法の良い例です

分離スコープは、トランスクルージョンでの使用にも最適です。タブを取ります。それらは機能全体であるだけでなく、その内部にあるものはすべて親スコープ内から自由に評価でき、タブ (およびペイン) は好きなように実行できます。タブには(テンプレートとやり取りする) スコープに属する独自の状態がありますが、その状態はそれが使用されたコンテキストとは関係ありません。さらに、タブで他のディレクティブを使用してもあまり意味がありません。それらはタブです - そして私たちはすでにその機能を持っています!

より多くの機能でそれを囲むか、より多くの機能をトランスクルードしますが、ディレクティブは既にあるものです。

そうは言っても、@ProLoserが彼の答えで示唆したように、isolateスコープの制限(つまり機能)のいくつかを回避する方法があることに注意する必要があります。たとえば、子スコープのセクションで、isolate スコープ (デフォルト) を使用した場合の非ディレクティブ属性の補間について説明しました。ただし、ユーザーは、たとえば、単に使用するだけで、class="item-type-{{$parent.item.type}}"再び機能する可能性があります。したがって、子スコープよりも分離スコープを使用するやむを得ない理由があるが、これらの制限のいくつかについて心配している場合は、必要に応じてほぼすべての制限を回避できることを知っておいてください。

概要

新しいスコープのないディレクティブは読み取り専用です。それらは完全に信頼されており (つまり、アプリの内部)、ジャックには触れません。子スコープを持つディレクティブは機能を追加しますが、それだけが機能ではありません。最後に、isolate スコープは、全体の目標であるディレクティブ用です。それらはスタンドアロンであるため、それらを悪者に任せても問題ありません (そして最も「正しい」)。

私は最初の考えを出したかったのですが、より多くのことを考えているので、これを更新します. しかし、聖なるがらくた-これはSOの答えには長いです...


PS: 完全に接線ですが、スコープについて話しているので、私は「プロトタイプ」と言う方が好きですが、他の人は「プロトタイプ」を好みます。:-)

于 2013-02-16T20:31:03.017 に答える
52

私の個人的なポリシーと経験:

分離:プライベート サンドボックス

ディレクティブでのみ使用され、ユーザーが表示したり直接アクセスしたりすることのない多くのスコープ メソッドと変数を作成したいと考えています。利用可能なスコープ データをホワイトリストに登録したいと考えています。トランスクルージョンを使用して、ユーザーが親スコープ (影響を受けない) に戻ることを許可できます。トランスクルージョンされた子で変数やメソッドにアクセスしたくありません。

子:コンテンツのサブセクション

ユーザーがアクセスできるスコープメソッドと変数を作成したいが、ディレクティブのコンテキスト外の周囲のスコープ (兄弟と親) には関係ありません。また、すべての親スコープ データを透過的に細流化させたいと考えています。

なし:シンプルな読み取り専用ディレクティブ

スコープのメソッドや変数をいじる必要はありません。おそらく、スコープとは関係のないことを行っています (単純な jQuery プラグインの表示、検証など)。

ノート

  • ngModel やその他の事柄が決定に直接影響を与えるべきではありません。ng-model=$parent.myVal(子供)またはngModel: '='(隔離)などのことを行うことで、奇妙な行動を回避できます。
  • Isolate + transcludeは、すべての通常の動作を兄弟ディレクティブに復元し、親スコープに戻るため、判断に影響を与えないようにしてください。
  • noneのスコープを台無しにしないでください。これは、DOM の下半分のスコープにデータを配置するようなものですが、上半分にはデータを配置しないため、意味がありません。
  • ディレクティブの優先順位に注意してください (これが物事にどのように影響するかについての具体的な例はありません)
  • サービスを注入するか、コントローラーを使用して、任意のスコープ タイプのディレクティブ間で通信します。require: '^ngModel'親要素を調べることもできます。
于 2013-02-17T01:56:11.917 に答える
18

isolated多くのディレクティブを作成した後、使用するスコープを減らすことにしました。クールで、データをカプセル化し、データが親スコープに漏れないように注意しても、一緒に使用できるディレクティブの量が大幅に制限されます。そう、

作成しようとしているディレクティブが完全に単独で動作し、それを他のディレクティブと共有しない場合は、分離スコープを使用してください。(コンポーネントのように、プラグインするだけで、最終開発者向けのカスタマイズはあまりありません) (内部にディレクティブを持つサブ要素を記述しようとすると、非常にトリッキーになります)

記述しようとしているディレクティブがスコープの内部状態を必要としない dom 操作、または明示的なスコープの変更 (ほとんどは非常に単純なもの) を行うだけの場合。新しいスコープはありません。( ngShowngMouseHover、 、ngClickなどngRepeat)

作成しようとしているディレクティブで、親スコープ内のいくつかの要素を変更する必要があるだけでなく、内部状態も処理する必要がある場合は、new child scopeを使用してください。(などngController)

ディレクティブのソース コードを確認してください: https://github.com/angular/angular.js/tree/master/src/ng/directive
ディレクティブ について考える方法に大いに役立ちます。

于 2013-02-16T19:43:53.523 に答える
9

現在の理解と、それが他の JS の概念とどのように関連しているかを追加したいと思いました。

デフォルト (宣言されていない、スコープ: false など)

これは、グローバル変数を使用することと哲学的に同等です。ディレクティブは親コントローラーのすべてにアクセスできますが、それらにも影響を与え、同時に影響を受けています。

範囲:{}

これはモジュールのようなもので、使用したいものはすべて明示的に渡す必要があります。使用するすべてのディレクティブが分離スコープである場合、すべての依存関係を注入する際に多くのオーバーヘッドを伴う独自のモジュールを作成するすべての JS ファイルを作成するのと同じになる可能性があります。

スコープ: 子

これは、グローバル変数と明示的なパススルーの中間です。これは JavaScript のプロトタイプ チェーンに似ており、親スコープのコピーを拡張するだけです。分離スコープを作成し、親スコープのすべての属性と関数を渡すと、機能的にはこれと同等になります。


重要なのは、ANY ディレクティブは ANY の方法で記述できるということです。さまざまなスコープ宣言は、整理するのに役立つだけです。すべてをモジュールにすることも、すべてのグローバル変数を使用して十分に注意することもできます。メンテナンスを容易にするために、ロジックを論理的に一貫性のある部分にモジュール化することをお勧めします。開いた牧草地と閉じた監獄の間にはバランスがあります。これが難しい理由は、人々がこれについて学ぶとき、ディレクティブがどのように機能するかについて学んでいると考えているが、実際にはコード/ロジックの構成について学んでいるからだと私は信じています。

ディレクティブがどのように機能するかを理解するのに役立ったもう 1 つのことは、ngInclude について学ぶことです。ngInclude は、html パーシャルを含めるのに役立ちます。最初にディレクティブを使い始めたとき、そのテンプレート オプションを使用してコードを削減できることがわかりましたが、実際にはロジックを追加していませんでした。

もちろん、angular のディレクティブとangular-uiチームの作業の間では、実質的なことを行う独自のディレクティブをまだ作成する必要がなかったため、これに関する私の見解は完全に間違っている可能性があります。

于 2014-03-27T23:03:02.203 に答える