Улучшить эту документацию Просмотреть исходный код $compile
- $compileProvider
- служба в модуле ng
Обзор
Компилирует строку HTML или DOM в шаблон и генерирует функцию шаблона, которая может быть использована для связывания scope и шаблона.
Компиляция — это процесс обхода дерева DOM и сопоставления элементов DOM с директивами.
Полный API директивы
Существует множество различных вариантов директивы.
Разница заключается в возвращаемом значении функции-фабрики. Вы можете вернуть объект определения директивы (см. ниже), определяющий свойства директивы, или просто функцию postLink, (все остальные свойства будут иметь значения по умолчанию).
Вот пример директивы, объявленной с помощью объекта определения директивы:
var myModule = angular.module(...);
myModule.directive('directiveName', function factory(injectables) {
var directiveDefinitionObject = {
priority: 0,
template: '<div></div>', // or // function(tElement, tAttrs) { ... },
// or
// templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
transclude: false,
restrict: 'A',
templateNamespace: 'html',
scope: false,
controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
controllerAs: 'stringIdentifier',
bindToController: false,
require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
multiElement: false,
compile: function compile(tElement, tAttrs, transclude) {
return {
pre: function preLink(scope, iElement, iAttrs, controller) { ... },
post: function postLink(scope, iElement, iAttrs, controller) { ... }
}
// or
// return function postLink( ... ) { ... }
},
// or
// link: {
// pre: function preLink(scope, iElement, iAttrs, controller) { ... },
// post: function postLink(scope, iElement, iAttrs, controller) { ... }
// }
// or
// link: function postLink( ... ) { ... }
};
return directiveDefinitionObject;
});
Следовательно, вышесказанное можно упростить следующим образом:
var myModule = angular.module(...);
myModule.directive('directiveName', function factory(injectables) {
var directiveDefinitionObject = {
link: function postLink(scope, iElement, iAttrs) { ... }
};
return directiveDefinitionObject;
// or
// return function postLink(scope, iElement, iAttrs) { ... }
});
Обработчики жизненного цикла
Контроллеры директивы могут предоставлять следующие методы, которые вызываются AngularJS в определённые моменты жизненного цикла директивы:
-
$onInit()— Вызывается для каждого контроллера после того, как все контроллеры на элементе были построены и их привязки были инициализированы (и до функций предварительной и последующей привязки для директивы на этом элементе). Это хорошее место для размещения кода инициализации для вашего контроллера. -
$onChanges(changesObj)— Вызывается всякий раз, когда происходит обновление односторонних (<) или интерполяционных (@) привязок.changesObj— это хеш, ключи которого представляют собой имена связанных свойств, которые изменились, а значения представляют собой объект типа{ currentValue, previousValue, isFirstChange() }. Используйте этот обработчик для запуска обновлений внутри компонента, например, для клонирования связанного значения, чтобы предотвратить случайное изменение внешнего значения. Обратите внимание, что это также будет вызвано при инициализации ваших привязок. -
$doCheck()— Вызывается на каждом шаге цикла обработки. Предоставляет возможность обнаружения и реагирования на изменения. Любые действия, которые вы хотите выполнить в ответ на обнаруженные изменения, должны быть вызваны из этого обработчика; реализация этого не влияет на время вызова$onChanges. Например, этот обработчик может быть полезен, если вы хотите выполнить проверку глубокого равенства или проверить объект Date, изменения которого не будут обнаружены детектором изменений AngularJS и, таким образом, не вызовут$onChanges. Этот обработчик вызывается без аргументов; если вы обнаруживаете изменения, вы должны сохранить предыдущее(ые) значение(я) для сравнения с текущими значениями. -
$onDestroy()— Вызывается для контроллера, когда содержащий его scope уничтожен. Используйте этот обработчик для освобождения внешних ресурсов, наблюдателей и обработчиков событий. Обратите внимание, что у компонентов вызываются обработчики$onDestroy()в том же порядке, что и события$scope.$broadcast, которые генерируются сверху вниз. Это означает, что у родительских компонентов обработчик$onDestroy()вызывается до дочерних компонентов. -
$postLink()— Вызывается после того, как элемент этого контроллера и его дочерние элементы были связаны. Аналогично функции после привязки, этот обработчик можно использовать для настройки обработчиков событий DOM и выполнения прямой манипуляции с DOM. Обратите внимание, что дочерние элементы, содержащие директивыtemplateUrl, не будут скомпилированы и связаны, поскольку они ожидают загрузки шаблона асинхронно и их собственная компиляция и связывание приостановлены до тех пор, пока это не произойдёт.
Сравнение с обработчиками жизненного цикла в новом Angular
Новый Angular также использует обработчики жизненного цикла для своих компонентов. Хотя обработчики жизненного цикла AngularJS похожи, есть некоторые различия, о которых вам следует знать, особенно при переносе вашего кода из AngularJS в Angular:
- Обработчики AngularJS имеют префикс
$, например$onInit. Обработчики Angular имеют префиксng, напримерngOnInit. - Обработчики AngularJS можно определять на прототипе контроллера или добавлять в контроллер внутри его конструктора. В Angular вы можете определять обработчики только на прототипе класса компонента.
- Из-за различий в обнаружении изменений вы можете получить гораздо больше вызовов
$doCheckв AngularJS, чем вызововngDoCheckв Angular. - Изменения модели внутри
$doCheckвызовут новые циклы обработки, которые приведут к распространению изменений по всему приложению. Angular не позволяет обработчикуngDoCheckзапускать изменения за пределами компонента. Он либо выдаст ошибку, либо ничего не сделает, в зависимости от состоянияenableProdMode().
Примеры обработчиков жизненного цикла
Этот пример показывает, как можно проверить изменения объекта Date, даже если идентичность объекта не изменилась.
Этот пример показывает, как можно использовать $doCheck для запуска изменений вводах вашего компонента, даже если фактическая идентичность компонента не изменяется. (Помните, что клонирование и проверки глубокого равенства на больших массивах или объектах могут негативно сказаться на производительности вашего приложения).
Объект определения директивы
Объект определения директивы предоставляет инструкции для компилятора. Атрибуты:
multiElement
Когда это свойство установлено в true (значение по умолчанию — false), компилятор HTML соберет узлы DOM между узлами с атрибутами directive-name-start и directive-name-end, и сгруппирует их вместе как элементы директивы. Рекомендуется использовать эту функцию для директивы, которая не является строго поведенческой (например, ngClick), и не манипулирует или не заменяет дочерние узлы (например, ngInclude).
priority
Когда для одного DOM-элемента определено несколько директивы, иногда необходимо указать порядок применения директивы. priority используется для сортировки директивы перед вызовом их функций compile. Приоритет определяется как число. Директивы с большим числовым priority компилируются первыми. Функции предварительной привязки также выполняются в порядке приоритета, но функции последующей привязки выполняются в обратном порядке. Порядок директивы с одинаковым приоритетом не определён. Приоритет по умолчанию — 0.
terminal
Если установлено в true, то текущая priority будет последним набором директивы, который будет выполнен (любые директивы с текущим приоритетом всё равно будут выполнены, поскольку порядок выполнения директивы с одинаковым priority не определён). Обратите внимание, что выражения и другие директивы, используемые в шаблоне директивы, также будут исключены из выполнения.
scope
Свойство scope может быть false, true, или объектом:
-
false(по умолчанию): Для директивы не будет создано scope. Директива будет использовать scope родительского элемента. -
true: Для элемента директивы будет создан новый дочерний scope, который прототипически наследует от родительского scope. Если несколько директивы на одном элементе запросят новый scope, будет создан только один новый scope. -
{...}(объект-хеш): Для шаблона директивы создаётся новый "изолированный" scope. "Изолированный" scope отличается от обычного scope тем, что он не наследует от родительского scope. Это полезно при создании повторно используемых компонентов, которые не должны случайно считывать или изменять данные в родительском scope. Обратите внимание, что директива с изолированным scope безtemplateилиtemplateUrlне будет применять изолированный scope к дочерним элементам.
Объект-хеш "изолированного" scope определяет набор локальных свойств scope, полученных из атрибутов элемента директивы. Эти локальные свойства полезны для алиасов значений для шаблонов. Ключи в объекте хеша соответствуют имени свойства в изолированном scope; значения определяют, как свойство привязано к родительскому scope, с помощью соответствующих атрибутов в элементе директивы:
-
@или@attr— привязывают свойство локального контекста к значению атрибута DOM. Результат всегда является строкой, так как атрибуты DOM — это строки. Если имяattrне указано, то предполагается, что имя атрибута совпадает с локальным именем. При заданном<my-component my-attr="hello {{name}}">и определении изолированного контекстаscope: { localName:'@myAttr' }, свойство контекста директивыlocalNameбудет отражать интерполированное значениеhello {{name}}. При изменении атрибутаnameбудет изменяться и свойствоlocalNameв контексте директивы. Значениеnameсчитывается из родительского контекста (не из контекста директивы). -
=или=attr— устанавливают двунаправленную привязку между свойством локального контекста и выражением, переданным через атрибутattr. Выражение вычисляется в контексте родительского контекста. Если имяattrне указано, то предполагается, что имя атрибута совпадает с локальным именем. При заданном<my-component my-attr="parentModel">и определении изолированного контекстаscope: { localModel: '=myAttr' }, свойствоlocalModelв контексте директивы будет отражать значениеparentModelв родительском контексте. Изменения вparentModelбудут отражаться вlocalModelи наоборот. Необязательные атрибуты должны быть помечены вопросительным знаком:=?или=?attr. Если выражение привязки не является присваиваемым или если атрибут не является необязательным и не существует, при обнаружении изменений в локальном значении будет выброшено исключение ($compile:nonassign), так как будет невозможно синхронизировать их обратно в родительский контекст. По умолчанию используется метод$watchдля отслеживания изменений, а проверка на равенство основана на тождестве объекта. Однако, если в качестве выражения привязки передаётся литерал объекта или литерал массива, проверка на равенство выполняется по значению (с использованием функцииangular.equals). Также можно отслеживать вычисленное значение поверхностно с помощью$watchCollection: используйте=*или=*attr(=*?или=*?attrесли атрибут является необязательным). -
<или<attr— устанавливают одностороннюю привязку между свойством локального контекста и выражением, переданным через атрибутattr. Выражение вычисляется в контексте родительского контекста. Если имяattrне указано, то предполагается, что имя атрибута совпадает с локальным именем. Вы также можете сделать привязку необязательной, добавив?:<?или<?attr.Например, при заданном
<my-component my-attr="parentModel">и определении директивыscope: { localModel:'<myAttr' }, свойство изолированного контекстаlocalModelбудет отражать значениеparentModelв родительском контексте. Любые изменения вparentModelбудут отражаться вlocalModel, но изменения вlocalModelне будут отражаться вparentModel. Однако есть два нюанса:- односторонняя привязка не копирует значение из родителя в изолированный контекст, она просто устанавливает то же значение. Это означает, что если привязанное значение является объектом, изменения его свойств в изолированном контексте будут отражаться в родительском контексте (поскольку оба ссылаются на один и тот же объект).
- односторонняя привязка отслеживает изменения идентичности родительского значения. Это означает, что
$watchдля родительского значения срабатывает только в случае изменения ссылки на значение. В большинстве случаев это не должно вызывать беспокойства, но это может быть важно, если вы производите одностороннюю привязку к объекту, а затем заменяете этот объект в изолированном контексте. Если вы теперь измените свойство объекта в родительском контексте, изменение не будет распространено на изолированный контекст, потому что идентичность объекта в родительском контексте не изменилась. Вместо этого вы должны назначить новый объект.
Односторонняя привязка полезна, если вы не планируете распространять изменения из вашего изолированного контекста обратно в родительский. Однако это не делает это совершенно невозможным.
-
&или&attr— позволяет выполнить выражение в контексте родительского контекста. Если имяattrне указано, то предполагается, что имя атрибута совпадает с локальным именем. При заданном<my-component my-attr="count = count + value">и определении изолированного контекстаscope: { localFn:'&myAttr' }, свойство изолированного контекстаlocalFnбудет ссылаться на обёртку функции для выраженияcount = count + value. Часто желательно передавать данные из изолированного контекста в родительский контекст через выражение. Это можно сделать, передав в обёртку функции выражения мапу из имён локальных переменных и их значений. Например, если выражение —increment(amount), то мы можем указать значение amount, вызвавlocalFnкакlocalFn({amount: 22}).
В общем случае можно применять несколько директивы к одному элементу, но могут быть ограничения в зависимости от типа контекста, требуемого директивами. Следующие пункты помогут объяснить эти ограничения. Для простоты рассматриваются только две директивы, но это также применимо для нескольких директивы:
- без контекста + без контекста => Две директивы, которые не требуют своего собственного контекста, будут использовать контекст родителя
- контекст дочернего элемента + без контекста => Обе директивы будут использовать один и тот же дочерний контекст
- контекст дочернего элемента + контекст дочернего элемента => Обе директивы будут использовать один и тот же дочерний контекст
- изолированный контекст + без контекста => Директива с изолированным контекстом будет использовать свой собственный созданный изолированный контекст. Другая директива будет использовать контекст родителя
- изолированный контекст + контекст дочернего элемента => Не сработает! Только один контекст может быть связан с одним элементом. Поэтому эти директивы нельзя применять к одному элементу.
- изолированный контекст + изолированный контекст => Не сработает! Только один контекст может быть связан с одним элементом. Поэтому эти директивы нельзя применять к одному элементу.
bindToController
Это свойство используется для привязки свойств контекста напрямую к контроллеру. Оно может быть либо true , либо объектом-хешем с тем же форматом, что и свойство scope.
Когда для директивы используется изолированный контекст (см. выше), bindToController: true позволит компоненту привязать свои свойства к контроллеру, а не к контексту.
После создания контроллера начальные значения привязок изолированного контекста будут привязаны к свойствам контроллера. Вы можете получить доступ к этим привязки после их инициализации, предоставив метод контроллера под названием $onInit, который вызывается после того, как все контроллеры на элементе были созданы и их привязки были инициализированы.
$compileProcvider.preAssignBindingsEnabled(true) был вызван, привязки для контроллеров, не являющихся классами ES6, привязываются к this до вызова конструктора контроллера, но это использование теперь устарело. Пожалуйста, поместите код инициализации, который полагается на привязки, внутри метода $onInit контроллера вместо этого. Также можно задать bindToController в виде объекта-хеша с тем же форматом, что и свойство scope . Это установит привязки контекста непосредственно к контроллеру. Обратите внимание, что scope по-прежнему может использоваться для определения типа создаваемого контекста. По умолчанию контекст не создаётся. Используйте scope: {} для создания изолированного контекста (полезно для директив компонентов).
Если оба bindToController и scope определены и содержат хеши объектов, то bindToController переопределяет scope.
controller
Конструктор контроллера. Контроллер создаётся до фазы предварительной привязки и может быть доступен другим директивам (см. атрибут require). Это позволяет директивам взаимодействовать друг с другом и дополнять поведение друг друга. Контроллер инжектируем (и поддерживает нотацию квадратных скобок) со следующими локалями:
-
$scope— Текущий контекст, связанный с элементом -
$element— Текущий элемент -
$attrs— Текущий объект атрибутов для элемента -
$transclude— Функция привязки трансляции, предварительно связанная с правильным контекстом трансляции:function([scope], cloneLinkingFn, futureParentElement, slotName):-
scope: (необязательно) переопределить контекст. -
cloneLinkingFn: (необязательно) аргумент для создания клонов исходного транслированного содержимого. -
futureParentElement(необязательно):- определяет родителя, к которому
cloneLinkingFnдобавит клонированные элементы. - по умолчанию:
$element.parent()соответственно$elementдляtransclude:'element'соответственноtransclude:true. - необходимо только для трансляций, которые могут содержать элементы, не являющиеся HTML (например, элементы SVG), и когда
cloneLinkingFnпередаётся, так как эти элементы необходимо создать и клонировать особым образом, когда они определены вне своих обычных контейнеров (например, как<svg>). - См. также свойство
directive.templateNamespace.
- определяет родителя, к которому
-
slotName: (необязательно) имя слота для трансляции. Если ложно (например,null,undefinedили''), то предоставляется стандартная трансляция. Функция$transcludeтакже имеет метод на ней,$transclude.isSlotFilled(slotName), который возвращаетtrue, если указанный слот содержит содержимое (т. е. один или несколько узлов DOM).
-
require
Требует другую директиву и вводит её контроллер в качестве четвёртого аргумента функции привязки. Свойство require может быть строкой, массивом или объектом:
- строка, содержащая имя директивы, передаваемое в функцию привязки
- массив, содержащий имена директив, передаваемые в функцию привязки. Аргумент, передаваемый в функцию привязки, будет массивом контроллеров в том же порядке, что и имена в свойстве
require - объект, значения свойств которого являются именами директив, передаваемых в функцию привязки. Аргумент, передаваемый в функцию привязки, также будет объектом с соответствующими ключами, значения которых будут содержать соответствующие контроллеры.
Если свойство require является объектом и bindToController имеет истинное значение, то необходимые контроллеры привязываются к контроллеру, используя ключи свойства require. Эта привязка происходит после того, как все контроллеры были созданы, но перед вызовом $onInit. Если имя необходимого контроллера совпадает с локальным именем (ключом), то имя можно опустить. Например, {parentDir: '^^'} эквивалентно {parentDir: '^^parentDir'}. Обратитесь к $compileProvider для примера использования. Если такой(ие) необходимый(ые) директива(ы) не найдены или директива не имеет контроллера, то генерируется ошибка (если не указана функция связи, и необходимые контроллеры не привязываются к контроллеру директивы, в этом случае проверка ошибок пропускается). Имя можно префиксровать:
- (без префикса) - Найти необходимый контроллер на текущем элементе. Выбросить ошибку, если не найден.
-
?- Попробовать найти необходимый контроллер или передатьnullфункцииlinkесли не найден. -
^- Найти необходимый контроллер, просматривая элемент и его предков. Выбросить ошибку, если не найден. -
^^- Найти необходимый контроллер, просматривая предков элемента. Выбросить ошибку, если не найден. -
?^- Попробовать найти необходимый контроллер, просматривая элемент и его предков, или передатьnullфункцииlinkесли не найден. -
?^^- Попробовать найти необходимый контроллер, просматривая предков элемента, или передатьnullфункцииlinkесли не найден.
controllerAs
Имя идентификатора для ссылки на контроллер в области видимости директивы. Это позволяет ссылаться на контроллер из шаблона директивы. Это особенно полезно, когда директива используется как компонент, т.е. со isolate областью видимости. Также возможно использовать его в директиве без isolate / new области видимости, но необходимо понимать, что ссылка controllerAs может перезаписать свойство, которое уже существует в родительской области видимости.
restrict
Строка подмножества EACM, которое ограничивает директиву определённым стилем объявления директивы. Если опущено, используются значения по умолчанию (элементы и атрибуты).
-
E- Имя элемента (по умолчанию):<my-directive></my-directive> -
A- Атрибут (по умолчанию):<div my-directive="exp"></div> -
C- Класс:<div class="my-directive: exp;"></div> -
M- Комментарий:<!-- directive: my-directive exp -->
templateNamespace
Строка, представляющая тип документа, используемый разметкой в шаблоне. AngularJS нуждается в этой информации, поскольку этим элементам необходимо создать и клонировать особым способом, когда они определяются за пределами своих обычных контейнеров, таких как <svg> и <math>.
-
html- Все корневые узлы в шаблоне являются HTML. Корневые узлы также могут быть элементами верхнего уровня, такими как<svg>или<math>. -
svg- Корневые узлы в шаблоне являются элементами SVG (исключая<math>). -
math- Корневые узлы в шаблоне являются элементами MathML (исключая<svg>).
Если templateNamespace не указано, то пространство имён считается html.
template
HTML разметка, которая может:
- Заменить содержимое элемента директивы (по умолчанию).
- Заменить сам элемент директивы (если
replaceимеет значение true — устаревший). - Оборачивать содержимое элемента директивы (если
transcludeимеет значение true).
Значение может быть:
- Строкой. Например,
<div red-on-hover>{{delete_str}}</div>. - Функцией, которая принимает два аргумента
tElementиtAttrs(описаны в API функцииcompileниже) и возвращает строковое значение.
templateUrl
Это аналогично template, но шаблон загружается из указанного URL-адреса асинхронно.
Поскольку загрузка шаблона асинхронна, компилятор приостановит компиляцию директив на этом элементе до тех пор, пока шаблон не будет решён. Тем временем он продолжит компиляцию и связывание элементов-братьев и родителей так, как если бы этот элемент не содержал никаких директив.
Компилятор не приостанавливает всю компиляцию, чтобы дождаться загрузки шаблонов, потому что это приведёт к «зависанию» всего приложения до тех пор, пока все шаблоны не будут загружены асинхронно — даже в случае, когда только одна вложенная директива имеет templateUrl.
Загрузка шаблона является асинхронной даже если шаблон был предварительно загружен в $templateCache
Вы можете указать templateUrl как строку, представляющую URL-адрес, или как функцию, которая принимает два аргумента tElement и tAttrs (описанные в API функции compile ниже) и возвращает строковое значение, представляющее URL-адрес. В обоих случаях URL-адрес шаблона передаётся через $sce.getTrustedResourceUrl.
replace (УСТАРЕЛО)
replace будет удалено в следующей основной версии — т.е. v2.0).
Указывает, что должен заменить шаблон. По умолчанию false.
-
true- шаблон заменит элемент директивы. -
false- шаблон заменит содержимое элемента директивы.
Процесс замены мигрирует все атрибуты/классы со старого элемента на новый. См. Руководство по директивам для примера.
Существует очень мало случаев, когда требуется замена элементов для работы приложения, основной из них — это повторно используемые пользовательские компоненты, которые используются в контекстах SVG (потому что SVG не работает с пользовательскими элементами в дереве DOM).
transclude
Извлечь содержимое элемента, где появляется директива, и сделать его доступным для директивы. Содержимое компилируется и предоставляется директиве в качестве функции трансляции. См. раздел Трансляция ниже.
compile
function compile(tElement, tAttrs, transclude) { ... }
Функция compile занимается преобразованием DOM шаблона. Поскольку большинство директив не производят преобразования шаблона, она часто не используется. Функция compile принимает следующие аргументы:
-
tElement- элемент шаблона - Элемент, где была объявлена директива. Безопасно производить преобразование шаблона только над элементом и дочерними элементами. -
tAttrs- атрибуты шаблона - Нормализованный список атрибутов, объявленных в этом элементе, общий для всех функций compile директив. -
transclude- [УСТАРЕЛО!] Функция связи трансляции:function(scope, cloneLinkingFn)
template или templateUrl объявление или ручную компиляцию внутри функции compile. transclude, которая передаётся в функцию compile, устарела, поскольку, например, не знает правильной внешней области видимости. Пожалуйста, используйте функцию transclude, которая передаётся в функцию link вместо неё. Функция compile может возвращать значение, которое может быть либо функцией, либо объектом.
-
возвращение функции (post-link) - эквивалентно регистрации функции link через свойство
linkобъекта конфигурации, когда функция compile пустая. -
возвращение объекта с зарегистрированными функциями через
preиpostсвойства - позволяет управлять тем, когда функция link должна вызываться во время фазы link. См. информацию о функциях pre-link и post-link ниже.
link
Это свойство используется только если свойство compile не определено.
function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
Функция link отвечает за регистрацию обработчиков событий DOM и обновление DOM. Она выполняется после клонирования шаблона. Именно здесь будет размещена основная логика директивы.
-
scope- Область видимости - Область видимости, используемая директивой для регистрации наблюдателей. -
iElement- элемент экземпляра - Элемент, где используется директива. Безопасно изменять потомков элемента только в функцииpostLink, так как потомки уже связаны. -
iAttrs- атрибуты экземпляра - Нормализованный список атрибутов, объявленных в этом элементе, общий для всех функций связывания директивы. -
controller- экземпляр(ы) контроллера, требуемый(е) директивой - Экземпляры разделяются между всеми директивами, что позволяет директивам использовать контроллеры как канал связи. Точное значение зависит от свойстваrequireдирективы:- не требуется(ют) контроллеры: собственный контроллер директивы или
undefined, если его нет -
string: экземпляр контроллера -
array: массив экземпляров контроллеров
Если требуемый контроллер не найден, а он необязателен, экземпляр
null, иначе выбрасывается ошибка Отсутствует необходимый контроллер.Обратите внимание, что вы также можете потребовать собственный контроллер директивы — он будет доступен как любой другой контроллер.
- не требуется(ют) контроллеры: собственный контроллер директивы или
-
transcludeFn- функция связывания трансклюзии, предварительно привязанная к правильной области видимости трансклюзии. Это то же самое, что и параметр$transcludeконтроллеров директивы, см. раздел о контроллере для получения подробностей.function([scope], cloneLinkingFn, futureParentElement).
Функция предварительного связывания
Выполняется до связывания дочерних элементов. Небезопасно выполнять преобразования DOM, так как функция связывания компилятора не сможет найти правильные элементы для связывания.
Функция пост-связывания
Выполняется после связывания дочерних элементов.
Обратите внимание, что дочерние элементы, содержащие директивы templateUrl не будут скомпилированы и связаны, поскольку они ожидают загрузки своего шаблона асинхронно, а их компиляция и связывание приостановлены до тех пор, пока это не произойдёт.
Безопасно выполнять преобразования DOM в функции пост-связывания для элементов, которые не ожидают разрешения своих асинхронных шаблонов.
Трансклюзия
Трансклюзия — это процесс извлечения набора элементов DOM из одной части DOM и их копирования в другую часть DOM, сохраняя при этом их связь с исходной областью видимости AngularJS, из которой они были взяты.
Трансклюзия используется (часто с ngTransclude) для вставки исходного содержимого элемента директивы в указанное место в шаблоне директивы. Преимущество трансклюзии перед просто ручным перемещением элементов DOM заключается в том, что содержимое трансклюзии имеет доступ к свойствам в области видимости, из которой оно было взято, даже если у директивы изолированная область видимости. См. Руководство по директивам.
Это позволяет виджету иметь частное состояние для своего шаблона, в то время как содержимое трансклюзии имеет доступ к своей исходной области видимости.
Существует три вида трансклюзии в зависимости от того, хотите ли вы трансклюдировать только содержимое элемента директивы, весь элемент или несколько частей содержимого элемента:
-
true- трансклюдировать содержимое (т.е. дочерние узлы) элемента директивы. -
'element'- трансклюдировать весь элемент директивы, включая любые директивы в этом элементе, определённые с более низким приоритетом, чем эта директива. При использовании свойствоtemplateигнорируется. -
{...}(хеш объекта): - сопоставить элементы содержимого с "слотами" трансклюзии в шаблоне.
Трансклюзия с несколькими слотами объявляется путём предоставления объекта для свойства transclude.
Этот объект является отображением, где ключи — это имя слота для заполнения, а значение — это селектор элемента, используемый для соответствия HTML слоту. Селектор элемента должен быть в нормализованной форме (например, myElement) и будет соответствовать стандартным вариантам элементов (например, my-element, my:element, data-my-element, и т. д.).
Для получения дополнительной информации ознакомьтесь с руководством по Сопоставлению директив
Если префикс селектора элемента ? , то этот слот необязателен.
Например, объект трансклюзии { slotA: '?myCustomElement' } сопоставляет элементы <my-custom-element> со слотом slotA, к которому можно получить доступ через функцию $transclude или через директиву ngTransclude.
Слоты, которые не помечены как необязательные (?) приведут к ошибке во время компиляции, если в содержимом трансклюзии нет соответствующих элементов. Если вы хотите узнать, был ли необязательный слот заполнен содержимым, вы можете вызвать $transclude.isSlotFilled(slotName) на функции трансклюзии, переданной в функцию связывания директивы и инжектируемой в контроллер директивы.
Функции трансклюзии
Когда директива запрашивает трансклюзию, компилятор извлекает её содержимое и предоставляет функцию трансклюзии функции link и controller директивы. Эта функция трансклюзии — специальная функция связывания, которая вернёт скомпилированное содержимое, связанное с новой областью видимости трансклюзии.
ngTransclude, то вам не нужно беспокоиться об этой функции, так как ngTransclude позаботится об этом за вас.Если вы хотите вручную управлять вставкой и удалением содержимого трансклюзии в вашей директиве, то вы должны использовать эту функцию трансклюзии. При вызове функции трансклюзии она возвращает объект jqLite/jQuery, содержащий скомпилированный DOM, который связан с правильной областью видимости трансклюзии.
При вызове функции трансклюзии вы можете передать функцию прикрепления клона. Эта функция принимает два параметра, function(clone, scope) { ... }, где clone — свежая скомпилированная копия вашего содержимого трансклюзии, а scope — новая созданная область видимости трансклюзии, к которой будет связан клон.
cloneFn (функцию прикрепления клона) при вызове функции трансклюзии, так как тогда вы получаете свежий клон исходного DOM и также имеете доступ к новой области видимости трансклюзии.Обычной практикой является прикрепление вашего содержимого трансклюзии (clone) к DOM внутри вашей функции прикрепления клона:
var transcludedContent, transclusionScope;
$transclude(function(clone, scope) {
element.append(clone);
transcludedContent = clone;
transclusionScope = scope;
});
Позже, если вы хотите удалить содержимое трансклюзии из вашего DOM, то вы также должны уничтожить связанную область видимости трансклюзии:
transcludedContent.remove(); transclusionScope.$destroy();
element.remove() для удаления), то вы также несете ответственность за вызов $destroy для области видимости трансклюзии.Встроенные директивы манипулирования DOM, такие как ngIf, ngSwitch и ngRepeat автоматически уничтожают свои клоны трансклюзии по мере необходимости, поэтому вам не нужно беспокоиться об этом, если вы просто используете ngTransclude для вставки трансклюзии в вашу директиву.
Области видимости трансклюзии
При вызове функции трансклюзии возвращается фрагмент DOM, предварительно привязанный к области видимости трансклюзии. Эта область видимости специальная, так как она является дочерней по отношению к области видимости директивы (и, следовательно, уничтожается при уничтожении области видимости директивы), но наследует свойства области видимости, из которой она была взята.
Например, рассмотрим директиву, которая использует трансклюзию и изолированную область видимости. Иерархия DOM может выглядеть так:
<div ng-app>
<div isolate>
<div transclusion>
</div>
</div>
</div>
Иерархия областей видимости $parent будет выглядеть так:
- $rootScope
- isolate
- transclusion
но области видимости будут наследоваться протопически от разных областей видимости до их $parent.
- $rootScope - transclusion - isolate
Атрибуты
Объект Атрибутов — передаётся в качестве параметра в функциях link() или compile(). Он имеет множество применений.
-
Доступ к нормализованным именам атрибутов: Директивы, такие как 'ngBind', могут быть выражены различными способами: 'ng:bind',
data-ng-bind, или 'x-ng-bind'. Объект атрибутов позволяет получить нормализованный доступ к атрибутам. -
Взаимодействие между директивами: Все директивы делят один экземпляр объекта атрибутов, что позволяет директивам использовать объект атрибутов для взаимодействия между директивами.
-
Поддержка интерполяции: Атрибуты интерполяции назначаются объекту атрибутов, что позволяет другим директивам читать интерполированное значение.
-
Наблюдение за изменениями интерполированных атрибутов: Используйте
$observeдля наблюдения за изменениями значения атрибутов, содержащих интерполяцию (например,src="{{bar}}"). Это не только очень эффективно, но и единственный способ легко получить фактическое значение, поскольку на этапе связывания интерполяция ещё не вычислена, и поэтому значение в это время установлено вundefined.
function linkingFn(scope, elm, attrs, ctrl) {
// get the attribute value
console.log(attrs.ngModel);
// change the attribute
attrs.$set('ngModel', 'new value');
// observe changes to interpolated attribute
attrs.$observe('ngModel', function(value) {
console.log('ngModel has changed value to ' + value);
});
}
module.directive. Приведённый ниже пример демонстрирует, как работает $compile.Известные проблемы
Двойная компиляция
Двойная компиляция возникает, когда уже скомпилированная часть DOM компилируется повторно. Это нежелательный эффект, который может привести к некорректному поведению директив, проблемам производительности и утечкам памяти. Обратитесь к разделу руководства по компилятору о двойной компиляции для подробного объяснения и способов её предотвращения.
Использование
$compile(element, transclude, maxPriority);
Аргументы
| Параметр | Тип | Подробности |
|---|---|---|
| element | stringDOMElement | Элемент или строка HTML, которые нужно скомпилировать в функцию шаблона. |
| transclude | function(angular.Scope, cloneAttachFn=) | Функция, доступная для директив — УСТАРЕВШАЯ. Примечание: Передача функции transclude в функцию $compile устарела, так как она, например, не будет использовать правильную внешнюю область видимости. Пожалуйста, передайте функцию transclude как parentBoundTranscludeFn в функцию link вместо этого. |
| maxPriority | number | Применить только директивы с приоритетом ниже заданного (только влияет на корневой(е) элемент(ы), а не на их потомков) |
Возвращаемое значение
function(scope, cloneAttachFn=, options=) |
Функция link, которая используется для связывания шаблона (элемента/дерева DOM) со scope. Где:
Вызов функции связывания возвращает элемент шаблона. Это либо исходный элемент, переданный, либо копия элемента, если После связывания представление не обновляется до вызова $digest, который обычно выполняется AngularJS автоматически. Если вам нужен доступ к связанному представлению, есть два способа:
Дополнительную информацию о работе компилятора см. в разделе «Компилятор HTML AngularJS» руководства разработчика. |
© 2010–2018 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://code.angularjs.org/1.6.9/docs/api/ng/service/$compile