Введение в наследование компонентов
AngularDart позволяет разработчикам создавать компоненты и директивы, аннотируя определения классов с помощью метаданных. Эти метаданные инструктируют компилятор сгенерировать код, необходимый для внедрения зависимостей, построения шаблона, привязки данных и т. Д.
До недавнего времени компилятор AngularDart не обрабатывал метаданные супертипов. Это означало, что совместное использование общих функций между различными компонентами и директивами посредством наследования требовало повторного объявления всех метаданных в каждом классе.
Посмотрим, как выглядел этот узор.
В этой статье мы будем возвращаться к следующему примеру, чтобы продемонстрировать преимущества наследования метаданных. Это упрощенный пример, взятый из официальных компонентов дизайна материалов для AngularDart, используемых в Google.
Здесь у нас есть простая директива, которая добавляет функциональность кнопки к ее элементу хоста. Если щелкнуть элемент хоста или сфокусироваться при нажатии клавиши ввода, он выдаст событие через выход trigger
. Его также можно отключить, чтобы предотвратить отправку событий. Эту логику можно повторно использовать для создания компонента кнопки с помощью наследования.
Теперь у нас есть компонент, который наследует поведение кнопки из директивы, но заметили необходимость повторно объявить прослушиватели ввода, вывода и хоста в аннотации производного компонента?
Начиная с версии 4.0, повторное объявление метаданных для производных типов больше не требуется!
Теперь MyButtonComponent
неявно имеет те же прослушиватели ввода, вывода и хоста, что и MyButtonDirective
, подобно тому, как класс обычно наследует свойства и методы. Теперь, когда вы увидели простой - и, надеюсь, убедительный - пример, давайте посмотрим, что именно является наследуемым и как это работает.
Что передается по наследству?
Следующие аннотации теперь наследуются от всех супертипов, включая суперклассы, интерфейсы и миксины.
@ContentChild
/@ContentChildren
@HostBinding
@HostListener
@Input
@Output
@ViewChild
/@ViewChildren
Это означает, что больше нет необходимости повторно объявлять какие-либо из приведенных выше аннотаций в производном классе.
Что не наследуется?
Шаблоны, стили и другие @Directive
параметры не наследуются. Наследуются только метаданные, привязанные к свойству или методу. Это решение было принято потому, что производные типы могут переопределять методы доступа и методы, ссылаясь на их исходную реализацию через super
, тогда как такого механизма не существует для значений, привязанных к другим метаданным.
Унаследованные метаданные неизменны
По-прежнему можно повторно объявлять аннотации в производных типах; однако изменение унаследованных метаданных или привязка их к другому свойству не допускается.
Это ограничение может быть снято в будущем, но на данный момент необходимо упростить инструментарий и обеспечить простую замену компонентов и директив.
Базовые типы метаданных
Интересное последствие возникает в результате наследования метаданных: классы, которые сами не являются директивами или компонентами, теперь могут быть аннотированы, чтобы они служили базовыми типами или миксинами для других. Давайте продолжим развивать наш пример, чтобы продемонстрировать.
Проблема с текущей реализацией компонента кнопки: на кнопке нельзя сфокусироваться. Это означает, что он недоступен и не может быть запущен с помощью прослушивателя нажатия клавиш. Эта проблема также присутствует в директиве button, если ее элемент хоста не может быть сфокусирован. Мы можем решить эту проблему, установив в директиве кнопки свойство tabindex
для хост-элемента.
MyButtonDirective
мог бы реализовать это напрямую, но давайте представим, что у нас есть другие компоненты, которым также потребуется настраиваемое поведение. Вместо этого мы создадим абстрактный класс, который может быть расширен или смешан с помощью директив или компонентов.
Теперь мы можем просто расширить или смешать HasTabIndex
, чтобы сделать директиву кнопки - и, следовательно, производный компонент - доступным для фокусировки.
Заключение
Мы видели, как наследуемые метаданные сокращают дублирование кода между компонентами и директивами с общей функциональностью. Кроме того, он должен улучшить читаемость, позволяя метаданным размещаться рядом с соответствующим полем или методом. Надеюсь, вы найдете эту функцию полезной при разработке и сопровождении ваших собственных проектов.