Миксины¶
Миксины классов — это паттерн для совместного использования кода между классами с помощью стандартного JavaScript. В отличие от шаблонов композиции "has-a", таких как reactive controllers, где класс может владеть контроллером для добавления поведения, миксины реализуют композицию "is-a", где миксин заставляет сам класс быть экземпляром разделяемого поведения.
Вы можете использовать миксины для настройки компонента Lit, добавляя API или переопределяя его обратные вызовы жизненного цикла.
Основы миксинов¶
Миксины можно рассматривать как "фабрики подклассов", которые переопределяют класс, к которому они применяются, и возвращают подкласс, дополненный поведением, указанным в миксине. Поскольку миксины реализуются с помощью стандартных выражений классов JavaScript, они могут использовать все идиомы, доступные для подклассов, такие как добавление новых полей/методов, переопределение существующих методов суперкласса и использование super
.
Для удобства чтения в примерах на этой странице опущены некоторые типы TypeScript для функций mixin. Подробности о правильной типизации миксинов в TypeScript см. в Mixins in TypeScript.
Чтобы определить миксин, напишите функцию, которая принимает superClass
и возвращает новый класс, расширяющий его, добавляя поля и методы по мере необходимости:
1 2 3 4 |
|
Чтобы применить миксин, просто передайте класс, чтобы сгенерировать подкласс с примененным миксином. Чаще всего пользователи применяют миксин непосредственно к базовому классу при определении нового класса:
1 2 3 |
|
Миксины также могут использоваться для создания конкретных подклассов, которые пользователи могут расширять как обычный класс, где миксин — это деталь реализации:
1 |
|
1 2 3 4 5 |
|
Поскольку миксины классов — это стандартный паттерн JavaScript, а не Lit-специфика, в сообществе есть много информации о том, как использовать миксины для повторного использования кода. Чтобы узнать больше о миксинах, вот несколько хороших ссылок:
- Class mixins на MDN
- Real Mixins with JavaScript Classes by Justin Fagnani
- Миксины в руководстве по TypeScript.
- Dedupe mixin library от open-wc, включая обсуждение того, когда использование миксинов может привести к дублированию, и как использовать библиотеку дедупирования, чтобы избежать этого.
- Mixin conventions с последующей библиотекой веб-компонентов Elix. Не являясь специфичной для Lit, содержит продуманные предложения по применению соглашений при определении миксинов для веб-компонентов.
Создание миксинов для LitElement¶
Миксины, применяемые к LitElement, могут реализовывать или переопределять любой из стандартных пользовательских жизненных циклов элементов, таких как constructor()
или connectedCallback()
, а также любой из реактивных жизненных циклов обновлений, таких как render()
или updated()
.
Например, следующий миксин будет регистрировать, когда элемент создан, подключен и обновлен:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Обратите внимание, что миксин всегда должен делать супервызов стандартных методов жизненного цикла пользовательского элемента, реализованных в LitElement
. При переопределении обратного вызова реактивного обновления жизненного цикла рекомендуется вызывать суперметод, если он уже существует в суперклассе (как показано выше с необязательным вызовом super.updated?()
).
Также обратите внимание, что миксины могут выполнять работу до или после базовой реализации стандартных обратных вызовов жизненного цикла, выбирая время вызова суперметода.
Миксины также могут добавлять реактивные свойства, стили и API к подклассифицируемому элементу.
Миксин в примере ниже добавляет реактивное свойство highlight
к элементу и метод renderHighlight()
, который пользователь может вызвать, чтобы обернуть некоторый контент. Когда свойство/атрибут highlight
установлено, обернутое содержимое окрашивается в желтый цвет.
Обратите внимание, что в приведенном примере пользователь миксина должен вызывать метод renderHighlight()
из своего метода render()
, а также позаботиться о том, чтобы добавить статические стили
, определенные миксином, в стили подкласса. Характер этого договора между миксином и пользователем зависит от определения миксина и должен быть задокументирован автором миксина.
Миксины в TypeScript¶
При написании миксинов LitElement
на TypeScript необходимо знать несколько деталей.
Типизация суперкласса¶
Вы должны ограничить аргумент superClass
типом класса, который, как вы ожидаете, будет расширяться пользователями, если таковые имеются. Этого можно добиться с помощью общего вспомогательного типа Constructor
, как показано ниже:
1 2 3 4 5 6 7 8 9 10 |
|
Приведенный выше пример гарантирует, что класс, передаваемый в миксин, расширяется от LitElement
, так что ваш миксин может полагаться на обратные вызовы и другие API, предоставляемые Lit.
Типизация подкласса¶
Хотя в TypeScript есть базовая поддержка вывода возвращаемого типа для подкласса, созданного с помощью шаблона mixin, у нее есть серьезное ограничение: выводимый класс не должен содержать членов с модификаторами доступа private
или protected
.
Поскольку LitElement
сам по себе имеет приватные и защищенные члены, по умолчанию TypeScript выдаст ошибку "Property '...' of exported class expression may not be private or protected." при возврате класса, расширяющего LitElement
.
Существует два обходных пути, оба из которых предполагают приведение возвращаемого типа из функции mixin, чтобы избежать вышеуказанной ошибки.
Когда миксин не добавляет новых публичных/защищенных API¶
Если ваш миксин переопределяет только методы или свойства LitElement
и не добавляет никаких новых API, вы можете просто привести сгенерированный класс к типу суперкласса T
, который был передан:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Когда миксин добавляет новый публичный/защищенный API¶
Если ваш миксин добавляет новый защищенный или публичный API, который пользователи должны иметь возможность использовать в своем классе, вам нужно определить интерфейс для миксина отдельно от реализации, а возвращаемый тип привести к пересечению интерфейса миксина и типа суперкласса:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Применение декораторов в миксинах¶
Из-за ограничений системы типов TypeScript декораторы (такие как @property()
) должны применяться к объявлению класса, а не к выражению класса.
На практике это означает, что миксины в TypeScript должны объявлять класс и затем возвращать его, а не возвращать выражение класса непосредственно из функции-стрелки.
Поддерживается:
1 2 3 4 5 6 7 8 9 10 11 |
|
Не поддерживается:
1 2 3 4 5 6 7 8 9 |
|