Каковы преимущества функции шаблона директивы в Angularjs?

Согласно документации, template может быть функцией, которая принимает два параметра, element и attributes, и возвращает строковое значение, представляющее шаблон. Он заменяет текущий элемент содержимым HTML. Процесс замены переносит все атрибуты и классы из старого элемента в новый.

Функция compile занимается преобразованием шаблона DOM. Он принимает три параметра: функцию element, attributes и transclude. Параметр transclude устарел. Он возвращает функцию link.

Похоже, что функции template и compile очень похожи и могут достигать одной и той же цели. Функция template определяет шаблон, а функция compile изменяет DOM шаблона. Однако это можно сделать и в самой функции template. Я не понимаю, зачем изменять шаблон DOM вне функции template. И наоборот, если DOM можно изменить в функции compile, то зачем нужна функция template?


person Maksym Bykovskyy    schedule 06.01.2014    source источник
comment
Если вы возвращаете строку, которая зависит от атрибутов из функции шаблона, используйте меньше кода, чем при компиляции, поскольку вам не нужно вводить $compile и использовать его. Вместо этого Angular сделает это внутри   -  person charlietfl    schedule 06.01.2014
comment
Я не очень понимаю. Не могли бы вы привести пример, пожалуйста? Вы говорите о возврате строки шаблона, которая использует значения attrs? Вот так "<div size=\"" + attrs.size + "\"></div>".   -  person Maksym Bykovskyy    schedule 08.01.2014
comment
да.. по вашему примеру. Но также может содержать некоторые условные выражения... if(attrs.type=='somVal') {return string1;}else{ return string2}   -  person charlietfl    schedule 08.01.2014
comment
Хорошо, я вижу, похоже на ‹input type=text|button|checkbox|...›, где атрибут не нужно компилировать.   -  person Maksym Bykovskyy    schedule 08.01.2014
comment
Там, где атрибут не нужно интерполировать, я должен сказать действительно.   -  person Maksym Bykovskyy    schedule 08.01.2014


Ответы (2)


Функцию компиляции можно использовать для изменения модели 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 шаблона на все, что вам нравится, если этого требует ваша директива.

В большинстве случаев tElem и iElem будут одним и тем же элементом 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 и возврата функции ссылки (или объекта с функцией предварительной и последующей ссылки).

В этом смысле вы можете думать о функции шаблона как о своего рода удобной функции, позволяющей не использовать функцию компиляции, если вам просто нужно заменить содержимое строковым значением.

Надеюсь, это поможет!

person jvandemo    schedule 06.01.2014
comment
Спасибо за попытку ответить на мой вопрос, но это не то, о чем я спрашивал. Мой вопрос был о преимуществах функции template: function(element, attrs) { return "<div></div>"; } по сравнению с функцией компиляции. - person Maksym Bykovskyy; 08.01.2014
comment
Я обновил ответ. Не стесняйтесь, дайте мне знать, если вам нужна дополнительная информация. Спасибо! - person jvandemo; 08.01.2014
comment
Скажете ли вы тогда, что нужно использовать либо шаблон, либо функцию компиляции? Потому что использование обоих кажется немного избыточным. - person Maksym Bykovskyy; 08.01.2014
comment
Да все верно. В большинстве случаев достаточно одного из двух. Какой из них зависит от того, хотите ли вы вернуть строку (функция шаблона) или управлять DOM программно (функция компиляции). - person jvandemo; 08.01.2014
comment
Хорошо, я думаю, что ваш ответ в сочетании с комментариями charlietfl дает мне хороший вариант использования функции шаблона. Спасибо! - person Maksym Bykovskyy; 08.01.2014
comment
Еще одно отличие состоит в том, что возвращаемая функция ссылки в функции компиляции не может включать область изоляции. - person TheChrisONeil; 08.01.2016

Одним из лучших способов использования функции шаблона является условное создание шаблона. Это позволяет автоматизировать создание шаблона на основе атрибута или любого другого условия.

Я видел несколько очень больших шаблонов, которые используют 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 различных внутренних директив в зависимости от типа. Вместо использования transclude я могу установить тип для внешней директивы, и функция шаблона сгенерирует правильный шаблон с правильной внутренней директивой.

Эта правильно отформатированная строка шаблона затем передается функции компиляции и т. д.

person Intervalia    schedule 13.03.2015
comment
Это правильный ответ, и он также должен быть принятым. В качестве доказательства обратите внимание, что Angular 1.5 и 2 настоятельно рекомендуют использовать компонент вместо директивы. Компонент не позволит вам определить пользовательские функции compile() или link(), но будет поощрять использование функции шаблона для случаев, подобных описанному в OP. - person jose.angel.jimenez; 08.06.2016
comment
Что, если вы настроите динамически data-type как в <my-item data-type="{{ $ctrl.someItem.dataType}}"></my-item>? Похоже, что функция шаблона увидит буквальные значения атрибутов, например. tAttr['data-type'] == '{{ $ctrl.someItem.dataType}}' вместо tAttr['data-type'] == 'first' :( - person Dimitry K; 29.03.2019
comment
Прошло слишком много времени с тех пор, как я использовал AngularJS. Но я, кажется, помню, что вы можете вызвать функцию $parse, чтобы получить значение из $ctrl.someItem.dataType. По крайней мере, я думаю, что это было $parse - person Intervalia; 29.03.2019
comment
Хм... Спасибо, это определенно шаг в правильном направлении. Это позволяет преобразовать строковое выражение в функцию, но для функции требуются два параметра (context, locals), из которых она будет разрешать фактическое выражение. А внутри функции template() $scope/context директивы не видно.... - person Dimitry K; 29.03.2019