AngularJS директивы. Жизненный цикл
О мануале
Данный мануал будет полезен разработчику, который уже знаком с основами AngularJS фреймворка и уже знает, как создавать свои директивы, знает, что такое объект определения директивы и его свойства, которые подробно описаны в официальной документации.В этом мануале мы детально рассмотрим жизненный цикл директив, разберём подробнее функции объекта определения директивы (link, compile, controller), определим порядок их выполнения и приведем особенности их использования.
Поехали!
При написании директивы для управления ее поведением можно использовать любое из следующих свойств объекта определения директивы: compile, link, controller. В них мы можем манипулировать разметкой, работать с дочерними элементами, реализовывать бизнес логику, присоединить обработчики событий и назначить наблюдателей (observers и watches) к атрибутам.Compile — это функция, которая преобразует шаблон DOM в angular приложение. Не все директивы выполняют преобразование шаблона, поэтому она часто не используется.
Link — это функция, которая отвечает за регистрацию DOM-обработчиков событий и за обновление DOM. Чаще всего здесь находится большая часть логики директивы.
Controller — это функция конструктора контроллера директивы.
Функции Compile и Link будут возвращать либо объект с функциями preLink и postLink, либо просто возвращать функцию, которая будет являться postLink.
- preLink — выполняется до того, как дочерние элементы директивы обработаны и связаны.
- postLink — выполняется после того, как дочерние элементы директивы обработаны и связаны.
Какое свойство и для каких целей лучше подходит, мы разберем чуть дальше, а пока подробно рассмотрим порядок их выполнения и жизненный цикл директивы.
Порядок выполнения
Для начала рассмотрим порядок выполнения функций controller, compile, preLink, postLink при инициализации директивы.Для одной директивы
Рассмотрим пример директивы log, которая делает вывод в консоль переданной строки на различных этапах своей загрузки.
HTML разметка:
JS код объявления директивы:
Вывод консоли будет следующим:
some-div (compile)
some-div (controller)
some-div (pre-link)
some-div (post-link)
На данном примере мы видим, что сначала выполняется compile, затем controller, далее preLink, и последняя postLink.
Для вложенных директив
Разметка HTML имеет древовидную структуру и поэтому очень часто элементы, содержащие директивы, могут иметь дочерние элементы, каждая со своей собственной директивой. Чтобы понять в каком порядке они обрабатываются, немного модернизируем HTML шаблон предыдущего примера и рассмотрим вывод в консоли.
HTML разметка:
Вывод консоли будет выглядеть так:
// The compile phase
parent (compile)
..first-child (compile)
..second-child (compile)
// The link phase
parent (controller)
parent (pre-link)
..first-child (controller)
..first-child (pre-link)
..first-child (post-link)
..second-child (controller)
..second-child (pre-link)
..second-child (post-link)
parent (post-link)
Здесь мы можем заметить, что загрузка вложенных директив начинается после функции preLink родительской директивы и ее функция postLink вызовется только после полного цикла загрузки всех дочерних директив.
Основные фазы
На предыдущем примере отчетливо видны две основные фазы загрузки директивы: фаза компиляции (compile phase) и фаза связывания или линковки (link phase). Давайте рассмотрим их подробнее.Компиляция
После загрузки HTML разметки браузером, AngularJS вызывает свою функцию $compile, которая также проходит по разметке сверху вниз и вызывает функцию compile у всех обнаруженных директив. Результатом выполнения этой функции является функция link, которая будет вызвана в фазе связывания.
Следующий график отображает этот процесс:
Связывание
На этой фазе AngularJS сперва вызывает функцию controller, которая создаст контроллер директивы. Далее вызовется функция preLink, затем будут обработаны директивы, найденные в дочерних элементах, и после этого вызывается функция postLink.Если элементы html добавляются динамически, например, с помощью директивы ng-repeat, то они также пройдут все фазы компиляции и связывания.
График фазы линковки:
Полный график фазы компиляции и связывания
На данном графике можно увидеть в какой момент происходит удаление исходного содержимого элемента директивы (Transcluded content removed), и сохранено в памяти для будущей вставки в шаблон директивы или для доступа в controller.Также отображено, на каком этапе директива получает html шаблон и в какой момент AngularJS создает область видимости (scope and isolate scope) для директивы.
Использование функций
Далее, мы рассмотрим отдельно основные функции объекта определения директивы, и определим для каких целей какая лучше подходит, и что реализовывать не рекомендуется.Функция компиляции
Это место для выполнения (исходных) манипуляций с шаблонами, которые еще не связаны с областью видимостью или привязкой данных.
Рекомендуется:
- Манипулировать разметкой, чтобы она служила шаблоном для экземпляров (клонов).
Не рекомендуется:
- Присоединять обработчики событий
- Работать с дочерними элементами
- Назначать наблюдателей (observers) по атрибутам
- Назначать наблюдателей (watches) на области видимости
Функция контроллера
Основное назначение функции контроллера:
- Определяет бизнес логику контроллера (методы).
- Определяет область видимости переменных
Не рекомендуется:
- Работать с дочерними элементами (они могут быть еще не отображены, и не привязаны к области видимости)
Функция Pre-link
Функция pre-link используется редко, но может быть полезна в специальных сценариях.
Например, когда дочерний контроллер регистрирует себя с родительским контроллером.
Сразу после вызова этой функции начнётся фаза связывания для дочерних элементов, для которых текущая область видимости будет служить родительской.
Не рекомендуется:
- Работать с дочерними элементами
Функция Post-link
Когда вызывается функция post-link, все предыдущие шаги завершились — подготовка шаблона, привязка данных и т. д. Если директива не содержит бизнес логики и не требует предварительной обработки шаблона, вы можете сразу использовать функцию объекта определения директивы link. В сокращенной записи она и будет являться функцией post-link.
Рекомендуется:
- Манипулировать элементы DOM
- Присоединять обработчики событий
- Работать с дочерними элементами
- Назначать наблюдателей (observers) по атрибутам
- Настройка наблюдателей (watches) на области видимости
Сравнительная таблица функций директивы
Для удобства вынесем все рекомендации по использованию функций директивы в отдельную таблицу.
Заключение
Четкое знание жизненного цикла директив AngularJS позволит разрабатывать более сложные компоненты приложения, реализовывать красивые инженерные решения сложных задач и предотвратит возникновение распространенных ошибок.Всем удачи и процветания!