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

Декораторы

Прежде чем я углублюсь в декораторы трафарета, давайте сначала разберемся, что такое декораторы. Декораторы - это функции, которые аннотируют и изменяют классы и свойства во время разработки. Вы можете просто смотреть на них как на крючок для добавления функциональности во время разработки. Фреймворки, такие как Angular, используют декораторы, чтобы помочь своему компилятору понять, как добавить соответствующие функции фреймворка (например, внедрение зависимостей или анимацию) в декорированный класс / свойство. В настоящее время декораторы представляют собой черновик ECMAScript stage 2, но их можно использовать с языком TypeScript.

В TypeScript есть 4 типа декораторов:

  • Класс
declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;
  • Имущество
declare type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void;
  • Метод
declare type MethodDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void;
  • Параметр
declare type ParameterDecorator = (target: Object, propertyKey: string | symbol, parameterIndex: number) => void;

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

@Component()

Stencil использует декораторы для аннотирования компонента и объяснения компилятору Stencil, как подключить компонент, который мы создаем.

Декораторы трафаретов

В @stencil/core можно найти следующие декораторы:

export declare const Component: ComponentDecorator;
export declare const Element: ElementDecorator;
export declare const Event: EventDecorator;
export declare const Listen: ListenDecorator;
export declare const Method: MethodDecorator;
export declare const Prop: PropDecorator;
export declare const PropWillChange: PropChangeDecorator;
export declare const PropDidChange: PropChangeDecorator;
export declare const State: StateDecorator;

У каждого декоратора своя цель, и в большинстве случаев вы не будете использовать их все в создаваемом компоненте. С другой стороны, хорошо знать их все, поскольку они могут понадобиться вам при разработке компонента, а список в настоящее время невелик.

Компонент

Главный декоратор, который вы собираетесь использовать, - это декоратор Component. Декоратор Component настраивает ваш компонент и включает одно обязательное свойство, которое является тегом tag компонента. При именовании тега следует соблюдать ограничение Пользовательские элементы - в названии компонента должен быть тире. Если вы забудете это ограничение, не волнуйтесь, потому что компилятор Stencil будет кричать на вас. Декоратор компонентов также может иметь следующие необязательные свойства:

styleUrl?: string;
styleUrls?: string[] | ModeStyles;
styles?: string;
shadow?: boolean;
host?: HostMeta;
assetsDir?: string;
assetsDirs?: string[];

Первые три свойства настраивают URL-адреса стиля или вы можете передать строку стиля. Свойство shadow определяет, нужно ли добавлять теневую DOM для обертывания компонента HTML или нет. AssetsDir / s настраивает, где искать компоненты, такие как изображения. Что касается свойства host, я ничего не нашел об этом в документации и полагаю, что это возможность каким-то образом настроить элемент хоста.

Пример использования декоратора компонентов:

import { Component } from '@stencil/core';
@Component({
    tag: 'st-toaster',
    styleUrl: 'toaster.scss',
    shadow: true
})
export class Toaster {
   ...
}

Элемент

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

Если вы работаете с Angular, он действительно похож на инъекционный элемент ElementRef.

Пример использования декоратора Element:

import { Component, Element } from '@stencil/core';
@Component({
   ...
})
export class Toaster {
    @Element() toasterDiv: HTMLElement;
    
    showToast() {
        this.toasterDiv.style.display = 'block';
    };
}

Декораторы событий и прослушивания

Декоратор Event позволяет отображать EventEmitter, который позже можно использовать для отправки событий настраиваемого компонента. Декоратор Listen позволяет прослушивать эти настраиваемые события в содержащихся компонентах. Например, вы можете предоставить событие toasterFadeOut, чтобы указать, что тост-сообщение закончилось:

import { Event, EventEmitter } from '@stencil/core';
@Component({
   ...
})
export class Toaster {
   @Event() toasterFadeOut: EventEmitter;
toasterFadeOutHandler() {
      this.toasterFadeOut.emit();
   }
}

Компонент, который использует событие, может выглядеть так:

import { Listen } from '@stencil/core';
export class ToasterApp {
    @Listen('toasterFadeOut')
    toasterFadeOutHandler(event: CustomEvent) {
       console.log('Received event: ', event.detail);
   }
}

Обратите внимание, что ToasterApp должен содержать излучающий компонент, иначе ничего не произойдет.

Listen также может принимать события всего приложения, такие как события прокрутки или клавиатуры. Вы можете посмотреть эту опцию на сайте трафаретов.

Метод

Декоратор Method используется для обозначения метода API, предоставляемого компонентом. Если вы хотите предоставить некоторые функции компонента, это способ сделать это:

import { Component, Element } from '@stencil/core';
@Component({
   ...
})
export class Toaster {
    @Element() toasterDiv: HTMLElement;    
    @Method()
    showToast(notification) {
        this.toasterDiv.textContent = notification;
        this.toasterDiv.style.display = 'block';
    };
}

Опора

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

context?: string;
connect?: string;
mutable?: boolean;

Нет документации по этим трем свойствам конфигурации, поэтому я добавлю объяснение того, что они делают в будущем.

Вы видели, как я использовал декоратор Prop в моем предыдущем посте, но давайте посмотрим его снова:

import {Component, Prop, State} from '@stencil/core';

@Component({
  tag: 'collapsible-panel',
  styleUrl: 'collapsible-panel.css'
})
export class CollapsiblePanel {
  @Prop() title: string;
  ...
}

PropWillChange и PropDidChange

PropWillChange и PropDidChange используются для подключения обработчиков перед изменением свойства и после изменения свойства. Эти хуки очень полезны, если вы хотите что-то сделать до и после изменения свойства. Например, вы можете добавить проверку перед изменением и выдать какое-либо событие после того, как произошло изменение свойства. Оба декоратора получают имя Prop, к которому они должны подключиться.

В следующем примере показано, как украсить title Prop:

import { Prop, PropDidChange, PropWillChange } from '@stencil/core';
  
export class CollapsiblePanel {
   @Prop() title: string;
   
   @PropWillChange('title')
   willChangeHandler(newValue: boolean) {
     console.log('The old title is:', this.title, 'The new title is: ', newValue);
   }
   @PropDidChange('title')
   didChangeHandler(newValue: boolean) {
     console.log('The new title is: ', newValue);
   }
 }

Штат

Последний декоратор - это State, который используется, чтобы указать, что член является частью состояния компонента. Любое изменение элемента, обозначенного как State, вызовет функцию компонента render.

Вы видели, как я использовал декоратор Prop в моем предыдущем посте, но давайте посмотрим его снова:

import {Component, Prop, State} from '@stencil/core';

@Component({
  tag: 'collapsible-panel',
  styleUrl: 'collapsible-panel.css'
})
export class CollapsiblePanel {
  @Prop() title: string;
  @State() collapsed: boolean;
  ...
}

Наш путь к декораторам трафаретов подошел к концу :)

Резюме

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