Продвинутые техники
📅
Наследование компонентов
Базовое наследование
class BaseButton extends HTMLElement {
constructor() {
super();
this.style.padding = '10px 20px';
this.style.border = 'none';
}
}
class PrimaryButton extends BaseButton {
constructor() {
super();
this.style.backgroundColor = 'blue';
this.style.color = 'white';
}
}
customElements.define('primary-button', PrimaryButton);
Переопределение методов
class SmartComponent extends HTMLElement {
connectedCallback() {
console.log('Базовая инициализация');
}
}
class AdvancedComponent extends SmartComponent {
connectedCallback() {
super.connectedCallback(); // Вызов родительского метода
console.log('Расширенная инициализация');
}
}
Миксины и примеси
Функции-миксины
function ClickableMixin(BaseClass) {
return class Clickable extends BaseClass {
constructor() {
super();
this.addEventListener('click', this.handleClick);
}
handleClick() {
console.log('Компонент клинут');
}
};
}
class BaseComponent extends HTMLElement {...}
const ClickableComponent = ClickableMixin(BaseComponent);
customElements.define('clickable-component', ClickableComponent);
Множественные миксины
function DraggableMixin(BaseClass) {
return class Draggable extends BaseClass {
// Реализация перетаскивания
};
}
function ResizableMixin(BaseClass) {
return class Resizable extends BaseClass {
// Реализация изменения размера
};
}
class AdvancedComponent extends DraggableMixin(ResizableMixin(HTMLElement)) {
constructor() {
super();
// Комбинированная функциональность
}
}
Паттерны композиции
Композиция через свойства
class TooltipComponent extends HTMLElement {
constructor() {
super();
this.tooltip = new TooltipService();
}
showTooltip() {
this.tooltip.show(this, 'Текст подсказки');
}
}
Делегирование методов
class FormComponent extends HTMLElement {
constructor() {
super();
this.validation = new ValidationService();
}
validate() {
return this.validation.validate(this);
}
// Делегирование метода
addValidationRule(rule) {
this.validation.addRule(rule);
}
}
Абстрактные компоненты
Базовые абстрактные классы
class AbstractComponent extends HTMLElement {
constructor() {
super();
if (new.target === AbstractComponent) {
throw new Error('AbstractComponent cannot be instantiated directly');
}
}
// Абстрактный метод
render() {
throw new Error('Method render() must be implemented');
}
}
class ConcreteComponent extends AbstractComponent {
render() {
// Конкретная реализация
this.innerHTML = '<div>Контент</div>';
}
}
Динамическая регистрация
Отложенная регистрация
// Динамическая регистрация по требованию
async function registerComponent(name, componentClass) {
if (!customElements.get(name)) {
customElements.define(name, componentClass);
}
}
// Использование
registerComponent('dynamic-component', DynamicComponent);
Условная регистрация
// Регистрация только если не существует
function safeDefine(name, componentClass) {
if (!customElements.get(name)) {
customElements.define(name, componentClass);
} else {
console.warn(`Component ${name} already registered`);
}
}
Best Practices
- Предпочитайте композицию наследованию
- Используйте миксины для cross-cutting concerns
- Избегайте глубоких иерархий наследования
- Документируйте абстрактные методы
- Проверяйте существование компонента перед регистрацией