Введение в наследование компонентов

AngularDart позволяет разработчикам создавать компоненты и директивы, аннотируя определения классов с помощью метаданных. Эти метаданные инструктируют компилятор сгенерировать код, необходимый для внедрения зависимостей, построения шаблона, привязки данных и т. Д.

До недавнего времени компилятор AngularDart не обрабатывал метаданные супертипов. Это означало, что совместное использование общих функций между различными компонентами и директивами посредством наследования требовало повторного объявления всех метаданных в каждом классе.

Посмотрим, как выглядел этот узор.

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

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

Теперь у нас есть компонент, который наследует поведение кнопки из директивы, но заметили необходимость повторно объявить прослушиватели ввода, вывода и хоста в аннотации производного компонента?

Начиная с версии 4.0, повторное объявление метаданных для производных типов больше не требуется!

Теперь MyButtonComponent неявно имеет те же прослушиватели ввода, вывода и хоста, что и MyButtonDirective, подобно тому, как класс обычно наследует свойства и методы. Теперь, когда вы увидели простой - и, надеюсь, убедительный - пример, давайте посмотрим, что именно является наследуемым и как это работает.

Что передается по наследству?

Следующие аннотации теперь наследуются от всех супертипов, включая суперклассы, интерфейсы и миксины.

  • @ContentChild / @ContentChildren
  • @HostBinding
  • @HostListener
  • @Input
  • @Output
  • @ViewChild / @ViewChildren

Это означает, что больше нет необходимости повторно объявлять какие-либо из приведенных выше аннотаций в производном классе.

Что не наследуется?

Шаблоны, стили и другие @Directive параметры не наследуются. Наследуются только метаданные, привязанные к свойству или методу. Это решение было принято потому, что производные типы могут переопределять методы доступа и методы, ссылаясь на их исходную реализацию через super, тогда как такого механизма не существует для значений, привязанных к другим метаданным.

Унаследованные метаданные неизменны

По-прежнему можно повторно объявлять аннотации в производных типах; однако изменение унаследованных метаданных или привязка их к другому свойству не допускается.

Это ограничение может быть снято в будущем, но на данный момент необходимо упростить инструментарий и обеспечить простую замену компонентов и директив.

Базовые типы метаданных

Интересное последствие возникает в результате наследования метаданных: классы, которые сами не являются директивами или компонентами, теперь могут быть аннотированы, чтобы они служили базовыми типами или миксинами для других. Давайте продолжим развивать наш пример, чтобы продемонстрировать.

Проблема с текущей реализацией компонента кнопки: на кнопке нельзя сфокусироваться. Это означает, что он недоступен и не может быть запущен с помощью прослушивателя нажатия клавиш. Эта проблема также присутствует в директиве button, если ее элемент хоста не может быть сфокусирован. Мы можем решить эту проблему, установив в директиве кнопки свойство tabindex для хост-элемента.

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

Теперь мы можем просто расширить или смешать HasTabIndex, чтобы сделать директиву кнопки - и, следовательно, производный компонент - доступным для фокусировки.

Заключение

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