StencilJS - компилятор web компонентов
Stencil - это компилятор, который создает веб-компоненты (custom elements).
Как заявляют авторы, Stencil объединяет лучшие концепции самых популярных фреймворков в простой инструмент. Stencil использует такие функции, как:
- Виртуальный DOM
- Асинхронный рендеринг (вдохновленный React Fiber)
- Реактивная привязка данных
- TypeScript
- JSX
Напишем простое модальное окно на StencilJS
Начнем
Нужен npm версии 6 и выше. Вводим команду npm init stencil
.
e:\home\js> npm init stencil
npx: installed 1 in 3.925s
√ Pick a starter » component
√ Project name » tyapk-modal
✔ All setup in 33 ms
Next steps:
> cd tyapk-modal
> npm start
Further reading:
- https://github.com/ionic-team/stencil-component-starter
Собственно переходим в папку и запускаемся npm start
. На http://localhost:3333/
нас приветствует страничка:
Hello, World! I'm Stencil 'Don't call me a framework' JS
Это пример встроенного веб-компонета.
Разметка и стили
HTML Разметка компонента:
<div class="dialog"> <!-- центрирующий содержимое fixed слой на весь экран, z-index = 1000 -->
<div class="dialog__content"> <!-- модальное окно -->
<header>
<h2>Заголовок модального окна</h2>
</header>
<main>
Содержимое окна
</main>
<footer>
<button class="dialog__ok-btn">OK</button>
<button class="dialog__cancel-btn">Отмена</button>
</footer>
<div class="dialog__close-btn"></div> <!-- кнопка Х "закрыть окно" -->
</div>
</div>
<div class="overlay"></div> <!-- слой затемнения на весь экран, z-index = 999 -->
СSS Стили компонента:
.overlay {
top: 0;
left: 0;
right: 0;
bottom: 0;
position: fixed;
background-color: rgba(52, 74, 94, 0.8);
z-index: 999;
overflow-x: hidden;
overflow-y: auto;
outline: none;
}
.dialog {
top: 0;
left: 0;
right: 0;
bottom: 0;
position: fixed;
z-index: 1000;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.dialog__content {
position: relative;
max-width: 520px;
margin-bottom: 5%;
background-color: white;
padding: 30px;
color: #344a5e;
border-radius: 5px;
box-shadow: 0 30px 30px 0 rgba(52, 74, 94, 0.8);
}
.dialog h2 {
margin: 0;
margin-bottom: 10px;
}
.dialog__ok-btn {
cursor: pointer;
height: 30px;
padding: 6px 15px;
margin-right: 15px;
min-width: 60px;
transition-duration: .25s;
transition-property: background-color, color;
text-align: center;
border-width: 1px;
border-style: solid;
border-radius: 3px;
box-shadow: 0 1px 2px 0 rgba(64, 61, 4, 0.44);
font-size: 14px;
color: white;
border-color: transparent;
background-color: #0279c0;
}
.dialog__cancel-btn {
cursor: pointer;
color: #0279c0;
background-color: transparent;
border-color: transparent;
box-shadow: none;
font-family: -apple-system, BlinkMacSystemFont, Ubuntu, 'Segoe UI', Roboto, Oxygen, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
.dialog__cancel-btn:hover {
text-decoration: underline;
}
.dialog__close-btn {
border: 0;
background: none;
position: absolute;
top: 20px;
right: 20px;
width: 15px;
height: 15px;
cursor: pointer;
}
// кнопка X
.dialog__close-btn::before, .dialog__close-btn::after {
position: absolute;
top: -2px;
right: 6px;
display: block;
width: 2px;
height: 19px;
content: '';
border-radius: 3px;
background-color: #d9d9d9;
}
.dialog__close-btn::before {
transform: rotate(45deg);
}
.dialog__close-btn::after {
transform: rotate(-45deg);
}
StencilJS
StencilJS так же как и Angular активно использует декораторы.
@Component()
- декоратор класса компонента. Задаёт общую информацию- используемый тег
- файл css стилей
- включение shadow dom
@Component({ tag: 'tyapk-modal', styleUrl: 'tyapk-modal.css', shadow: true }) export class TyapkModalComponent {}
@Prop()
- декоратор "входящего" атрибута/свойства компонента. Способ получить данные извне. Механизм отправить данные из родительского компонента в дочерний. По-умолчаниюimmutable
. Можно явно разрешить мутацию через({ mutable: true })
. В модальном окне заголовок будет задаваться через@Prop()
/** Header */ @Prop() header: string;
Использование:
<tyapk-modal header="Мамкин программист"></tyapk-modal>
@State()
- декоратор свойства компонента. Хранит внутреннее данные компонента. Данные не могут быть изменены снаружи компонента, но компонент может изменить их так, как считает нужным. Любые изменения@State()
свойства приведут перерисовке компонента. В модальном окне будет хранится состояние открытости/закрытости компонента./** Whether the model is open or not */ @State() private _show = false;
@Event()
- декортор свойства компонента. Способ отправить данные "наружу" или родительскому компоненту. Выкидает Custom DOM events события. В модальном окне будет выкидываться событие "закрытие окна" с информацией, что нажато (ОК, Отмена, крестик)./** Close event */ @Event() private close: EventEmitter; ... handleClick() { this._show = false; this.close.emit('ok'); } closeModal(result: 'cancel'|'close') { this._show = false; this.close.emit(result); }
При использовании компоненте на custom event подписываются как на обычные события:
document.querySelector('tyapk-modal').addEventListener('close', function ($) { console.log('Результат: ', $); });
Никаких препроцессоров HTML или CSS в StencilJS нет. В качестве шаблонизатора используется JSX. Насколько точно он соответствует React мне трудно судить. В модальном окне у меня получился такой шаблон:
render() {
if (this._show) {
return (
<div>
<div class="dialog">
<div class="dialog__content">
<header>
<h2>{this.header}</h2>
</header>
<main>
<slot />
</main>
<footer>
<button class="dialog__ok-btn" onClick={() => this.handleClick()}>OK</button>
<button class="dialog__cancel-btn" onClick={() => this.closeModal('cancel')}>Отмена</button>
</footer>
<div class="dialog__close-btn" onClick={() => this.closeModal('close')}></div>
</div>
</div>
<div class="overlay"></div>
</div>
);
}
}
Результат на github
При билде StencilJS создаёт набор js файлов, чтобы оптимизировать загрузку по уровню поддержки браузерами определенных возможностей.
Пример использования модального окна
<tyapk-modal header="Tyapk">
<p>У меня была одна проблема, поэтому я решил написать программу, которая её решит.
Теперь у меня есть 1 проблема, 9 ошибок и 12 предупреждений.</p>
</tyapk-modal>
Работает корректно в браузерах с поддержкой slot&template.
Вместо заключения.
С учётом того, что css стили были готовы разобраться в StencilJS и написать такой компонент у меня заняло 4 часа. Это безусловно намного меньше, чем разобраться с "голыми" веб-компонентами и написать веб-компонент с нуля (несколько дней).