Advanced Techniques
📅
Component Inheritance
Basic Inheritance
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);
Method Overriding
class SmartComponent extends HTMLElement {
connectedCallback() {
console.log('Base initialization');
}
}
class AdvancedComponent extends SmartComponent {
connectedCallback() {
super.connectedCallback(); // Call parent method
console.log('Extended initialization');
}
}
Mixins and Composition
Mixin Functions
function ClickableMixin(BaseClass) {
return class Clickable extends BaseClass {
constructor() {
super();
this.addEventListener('click', this.handleClick);
}
handleClick() {
console.log('Component clicked');
}
};
}
class BaseComponent extends HTMLElement {...}
const ClickableComponent = ClickableMixin(BaseComponent);
customElements.define('clickable-component', ClickableComponent);
Multiple Mixins
function DraggableMixin(BaseClass) {
return class Draggable extends BaseClass {
// Drag implementation
};
}
function ResizableMixin(BaseClass) {
return class Resizable extends BaseClass {
// Resize implementation
};
}
class AdvancedComponent extends DraggableMixin(ResizableMixin(HTMLElement)) {
constructor() {
super();
// Combined functionality
}
}
Composition Patterns
Property Composition
class TooltipComponent extends HTMLElement {
constructor() {
super();
this.tooltip = new TooltipService();
}
showTooltip() {
this.tooltip.show(this, 'Tooltip text');
}
}
Method Delegation
class FormComponent extends HTMLElement {
constructor() {
super();
this.validation = new ValidationService();
}
validate() {
return this.validation.validate(this);
}
// Method delegation
addValidationRule(rule) {
this.validation.addRule(rule);
}
}
Abstract Components
Base Abstract Classes
class AbstractComponent extends HTMLElement {
constructor() {
super();
if (new.target === AbstractComponent) {
throw new Error('AbstractComponent cannot be instantiated directly');
}
}
// Abstract method
render() {
throw new Error('Method render() must be implemented');
}
}
class ConcreteComponent extends AbstractComponent {
render() {
// Concrete implementation
this.innerHTML = '<div>Content</div>';
}
}
Dynamic Registration
Lazy Registration
// Dynamic on-demand registration
async function registerComponent(name, componentClass) {
if (!customElements.get(name)) {
customElements.define(name, componentClass);
}
}
// Usage
registerComponent('dynamic-component', DynamicComponent);
Conditional Registration
// Register only if not exists
function safeDefine(name, componentClass) {
if (!customElements.get(name)) {
customElements.define(name, componentClass);
} else {
console.warn(`Component ${name} already registered`);
}
}
Best Practices
- Prefer composition over inheritance
- Use mixins for cross-cutting concerns
- Avoid deep inheritance hierarchies
- Document abstract methods
- Check component existence before registration