534

ディレクティブを作成すると、コードをコンパイラ、リンク関数、またはコントローラに入れることができます。

ドキュメントでは、次のように説明しています。

  • コンパイルおよびリンク機能は、角度サイクルのさまざまなフェーズで使用されます
  • コントローラーはディレクティブ間で共有されます

ただし、どの種類のコードをどこに配置すればよいかは明確ではありません。

例: コンパイルで関数を作成し、それらをリンクのスコープにアタッチするか、コントローラーのスコープにのみ関数をアタッチすることはできますか?

各ディレクティブが独自のコントローラーを持つことができる場合、コントローラーはディレクティブ間でどのように共有されますか? コントローラーは本当に共有されていますか、それとも単にスコープのプロパティですか?

4

6 に答える 6

474

コンパイル:

これは、Angular がディレクティブを実際にコンパイルするフェーズです。このコンパイル関数は、指定されたディレクティブへの参照ごとに 1 回だけ呼び出されます。たとえば、ng-repeat ディレクティブを使用しているとします。ng-repeat は、添付されている要素を検索し、添付されている html フラグメントを抽出して、テンプレート関数を作成する必要があります。

HandleBars、アンダースコア テンプレート、または同等のものを使用したことがある場合は、それらのテンプレートをコンパイルしてテンプレート関数を抽出するようなものです。このテンプレート関数にデータを渡すと、その関数の戻り値は適切な場所にデータを含む html になります。

コンパイル フェーズは、テンプレート関数を返す Angular のステップです。angular のこのテンプレート関数は、リンク関数と呼ばれます。

リンクフェーズ:

リンク フェーズでは、データ ( $scope ) をリンク関数に添付し、リンクされた html を返す必要があります。ディレクティブは、この html の移動先や変更内容も指定しているため、これで問題ありません。これは、リンクされた html、つまり既にデータが添付されている html に変更を加えたい関数です。angularでは、リンク関数にコードを記述する場合、通常はリンク後関数です(デフォルト)。これは、リンク関数がデータをテンプレートにリンクした後に呼び出される一種のコールバックです。

コントローラー:

コントローラーは、ディレクティブ固有のロジックを配置する場所です。このロジックはリンク機能にも使用できますが、そのロジックをスコープに配置して「共有可能」にする必要があります。それに関する問題は、実際には期待されていないディレクティブでスコープを破損することです。では、2 つのディレクティブが互いに話したり、協力したりしたい場合の代替手段は何ですか? もちろん、そのすべてのロジックをサービスに入れ、これらの両方のディレクティブをそのサービスに依存させることもできますが、それはもう 1 つの依存関係をもたらすだけです。別の方法は、このスコープにコントローラーを提供し (通常はスコープを分離しますか?)、そのディレクティブが別のディレクティブを「必要とする」場合に、このコントローラーを別のディレクティブに挿入します。

于 2013-03-28T11:58:06.113 に答える
100

また、Google チームによる O'Reily AngularJS book の内容を追加したいと思います。

コントローラー - ディレクティブ間で通信するための API を公開するコントローラーを作成します。良い例は、Directive to Directive Communicationです。

リンク - 結果の DOM 要素インスタンスをプログラムで変更し、イベント リスナーを追加し、データ バインディングを設定します。

コンパイル - ng-repeat で使用される場合のように、ディレクティブのコピー全体で機能の DOM テンプレートをプログラムで変更します。コンパイル関数はリンク関数を返して、結果の要素インスタンスを変更することもできます。

于 2014-06-04T19:59:44.587 に答える
10

これはディレクティブ フェーズを理解するための良いサンプルです http://codepen.io/anon/pen/oXMdBQ?editors=101

var app = angular.module('myapp', [])

app.directive('slngStylePrelink', function() {
    return {
        scope: {
            drctvName: '@'
        },
        controller: function($scope) {
            console.log('controller for ', $scope.drctvName);
        },
        compile: function(element, attr) {
            console.log("compile for ", attr.name)
            return {
                post: function($scope, element, attr) {
                    console.log('post link for ', attr.name)
                },
                pre: function($scope, element, attr) {
                    $scope.element = element;
                    console.log('pre link for ', attr.name)
                        // from angular.js 1.4.1
                    function ngStyleWatchAction(newStyles, oldStyles) {
                        if (oldStyles && (newStyles !== oldStyles)) {
                            forEach(oldStyles, function(val, style) {
                                element.css(style, '');
                            });
                        }
                        if (newStyles) element.css(newStyles);
                    }

                    $scope.$watch(attr.slngStylePrelink, ngStyleWatchAction, true);

                    // Run immediately, because the watcher's first run is async
                    ngStyleWatchAction($scope.$eval(attr.slngStylePrelink));
                }
            };
        }
    };
});

html

<body ng-app="myapp">
    <div slng-style-prelink="{height:'500px'}" drctv-name='parent' style="border:1px solid" name="parent">
        <div slng-style-prelink="{height:'50%'}" drctv-name='child' style="border:1px solid red" name='child'>
        </div>
    </div>
</body>
于 2015-07-18T15:28:54.297 に答える
8
  • compile : 新しい式を追加する、このディレクティブ内に別のディレクティブを追加するなど、ディレクティブ テンプレートを変更する必要がある場合に使用します。
  • controller : $scope データを共有/再利用する必要がある場合に使用
  • link : イベントハンドラーをアタッチしたり、DOM を操作したりする必要がある場合に使用する関数です。
于 2017-06-22T14:50:35.140 に答える