web-dev-qa-db-ja.com

Angularjsのディレクティブテンプレート関数の利点は何ですか?

ドキュメントによると、templateは、elementattributesの2つのパラメーターを取り、テンプレートを表す文字列値を返す関数になります。現在の要素をHTMLのコンテンツに置き換えます。置換プロセスは、すべての属性とクラスを古い要素から新しい要素に移行します。

compile関数は、テンプレートDOMの変換を処理します。 elementattributestransclude関数の3つのパラメーターを取ります。 transcludeパラメーターは非推奨になりました。 link関数を返します。

templatecompile関数は非常に似ており、同じことを達成できるようです。 template関数はテンプレートを定義し、compile関数はテンプレートDOMを変更します。ただし、template関数自体で実行できます。 template関数の外でテンプレートDOMを変更する理由がわかりません。逆に、DOMをcompile関数で変更できる場合、template関数の必要性は何ですか?

35

コンパイル関数を使用すると、結果のテンプレート関数がスコープにバインドされる前にDOMを変更できます。

次の例を考えてみましょう。

<div my-directive></div>

コンパイル機能を使用して、次のようにテンプレートDOMを変更できます。

app.directive('myDirective', function(){
  return {

    // Compile function acts on template DOM
    // This happens before it is bound to the scope, so that is why no scope
    // is injected
    compile: function(tElem, tAttrs){

      // This will change the markup before it is passed to the link function
      // and the "another-directive" directive will also be processed by Angular
      tElem.append('<div another-directive></div>');

      // Link function acts on instance, not on template and is passed the scope
      // to generate a dynamic view
      return function(scope, iElem, iAttrs){

        // When trying to add the same markup here, Angular will no longer
        // process the "another-directive" directive since the compilation is
        // already done and we're merely linking with the scope here
        iElem.append('<div another-directive></div>');
      }
    }
  }
});

そのため、ディレクティブで必要な場合は、compile関数を使用してテンプレートDOMを好きなものに変更できます。

ほとんどの場合、tElemiElemは同じDOM要素ですが、ディレクティブがテンプレートを複製して複数のコピーを打ち消すと異なる場合があります(ngRepeatを参照) 。

舞台裏では、Angularは双方向のレンダリングプロセス(コンパイル+リンク)を使用して、DOMのコンパイルされた部分のコピーを打ち抜き、Angular=ディレクティブが複数のクローンを打ち抜いてパフォーマンスを大幅に向上させる場合に、各インスタンスで同じDOMを何度も処理(=ディレクティブを解析)する必要があります。

お役に立てば幸いです!


コメントの後に追加:

template関数とcompile関数の違い:

テンプレート機能

{
    template: function(tElem, tAttrs){

        // Generate string content that will be used by the template
        // function to replace the innerHTML with or replace the
        // complete markup with in case of 'replace:true'
        return 'string to use as template';
    }
}

コンパイル機能

{
    compile: function(tElem, tAttrs){

        // Manipulate DOM of the element yourself
        // and return linking function
        return linkFn(){};
    }
}

テンプレート関数は、コンパイル関数が呼び出される前に呼び出されます。

ほぼ同一のものを実行し、同じ「署名」を共有できますが、重要な違いは、テンプレート関数の戻り値がディレクティブのコンテンツ(またはreplace: true)、コンパイル関数はプログラムでDOMを変更し、リンク関数(または事前リンク関数と事後リンク関数を持つオブジェクト)を返すことが期待されます。

その意味で、テンプレート関数は、単にコンテンツを文字列値に置き換える必要がある場合に、コンパイル関数を使用する必要がないためのある種の便利な関数と考えることができます。

お役に立てば幸いです!

50
jvandemo

テンプレート関数の最適な使用法の1つは、条件付きでテンプレートを生成することです。これにより、属性またはその他の条件に基づいてテンプレートの作成を自動化できます。

ng-ifを使用してテンプレートのセクションを非表示にする非常に大きなテンプレートを見てきました。ただし、すべてをテンプレートに配置してng-ifを使用すると(過剰なバインドが発生する可能性があります)、使用されないテンプレート関数の出力からDOMのセクションを削除できます。

サブディレクティブitem-firstまたはitem-secondのいずれかを含むディレクティブがあるとします。また、サブディレクティブは、外部ディレクティブの存続期間中は変更されません。コンパイル関数が呼び出される前に、テンプレートの出力を調整できます。

<my-item data-type="first"></my-item>
<my-item data-type="second"></my-item>

これらのテンプレート文字列は次のとおりです。

<div>
  <item-first></item-first>
</div>

そして

<div>
  <item-second></item-second>
</div>

これは極端な単純化であることに同意しますが、いくつかの非常に複雑なディレクティブがあり、外部ディレクティブは、タイプに基づいて、約20の異なる内部ディレクティブのいずれかを表示する必要があります。トランスクルードを使用する代わりに、外部ディレクティブにタイプを設定し、テンプレート関数に正しい内部ディレクティブを使用して正しいテンプレートを生成させることができます。

次に、正しくフォーマットされたテンプレート文字列は、コンパイル関数などに渡されます。

6
Intervalia