Pierwszy komponent w Polymerze
Jest to wpis rozpoczynający serię o bibliotece Polymer, w którym pokażę jak zrobić element okna modalnego. Z racji tego, że jest to pierwszy wpis, zacznę od wyjaśnienia, w jaki sposób instaluje się bibliotekę i jak jej używać, a dopiero potem przejdę do tematu głównego, czyli kodu Custom Elementu.
Web Components – co to takiego
Zanim jednak zaczniemy używać Polymera, wypadałoby najpierw zrozumieć, czym właściwie są web componenty, bo właśnie na tej technologii bazuje Polymer. Wchodząc na stronę główną tejże biblioteki, naszym oczom ukaże się informacja:
Unlock the Power of Web Components. Polymer is a JavaScript library that helps you create custom reusable HTML elements, and use them to build performant, maintainable apps.
A zatem Polymer jest biblioteką, która umożliwia używanie Web Components już dziś, a dodatkowo upraszcza sposób ich implementacji oraz udostępnia narzędzia do budowania i testowania komponentów.
No dobra, ale dalej nie wyjaśniłem, co to są te Web Components. Jako że jestem leniwy, a poza tym jest to obszerne zagadnienie, po prostu udostępnię odnośniki do dobrych materiałów na ten temat.
- Web Components – Artykuł Comandeera
- Webcomponents.org – Introduction
- Custom Elements v1: Reusable Web Components
- Custom element concepts
Tworzenie nowego projektu
Przed utworzeniem projektu należy zainstalować Polymer CLI. Do zainstalowania wymagany jest również Bower, a zatem musimy wykonać dwie komendy:
npm install -g bower
npm install -g polymer-cli
Kiedy mamy już dostęp do komendy polymer
, możemy utworzyć nowy projekt poprzez wpisanie komendy:
polymer init
Na liście wyboru należy zaznaczyć polymer-2-element, a w polu Element name
podajemy nazwę naszego elementu np. polymer-modal.
W tym momencie powinna zostać utworzona struktura katalogów, jak również powinny się zainstalować zależności,
natomiast w pliku polymer-modal.html
(w zależności od tego, jaką podaliście nazwę) został umieszczony przykładowy kod.
Aby otworzyć komponent w przeglądarce, trzeba wykonać komendę polymer serve
.
Nie powinno nikogo dziwić, że po otworzeniu adresu skopiowanego z okna konsoli, wyświetli się strona z
jakimś randomowym napisem – projekt na razie jest pusty.
Robimy Custom Element
Zacznę trochę nietypowo, czyli od zmodyfikowania pliku index.html
, który od teraz będzie
zawierał taki kod:
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="utf-8">
<title>polymer-modal</title>
<script src="bower_components/webcomponentsjs/webcomponents-loader.js"></script>
<link rel="import" href="polymer-modal.html">
</head>
<body>
<polymer-modal>
<h1 slot="title">Nagłówek okna</h1>
<div slot="content">
<p>Akapit umieszczony w oknie.</p>
</div>
<span slot="close-label">Zamknij</span>
</polymer-modal>
</body>
</html>
W sekcji head
umieszczono dwie ważne linijki. Pierwsza z nich to skrypt webcomponents-loader.js
, który jest
konieczny po to, żeby nasz komponent działał w różnych przeglądarkach.
Druga linia, która odnosi się do pliku polymer-modal.html
to tzw. HTML Import.
Służy on, jak sama nazwa wskazuje, do zaimportowania pliku HTML, w którym będziemy trzymać kod komponentu.
W body umieściłem znacznik elementu polymer-modal
, chciałbym zwrócić uwagę na nazwę znacznika,
która składa się z dwóch członów rozdzielonych myślnikiem, taką konwencję nazewnictwa narzuca
specyfikacja Custom Elementów.
Wewnątrz znacznika znajdują się trzy elementy, kolejno: nagłówek okna, kontener treści i etykieta przycisku
zamykania (zamiast tekstu można umieścić ikonę). Kolejność znaczników nie będzie miała żadnego znaczenia,
to co jest ważne to atrybut slot, o którego znaczeniu dowiedzie się potem.
Główny plik komponentu
Każdy element posiada swoje własne drzewo elementów, które jest wyodrębnione od głównego drzewa dokumentu,
jest to tzw. Shadow DOM.
Nasz element polymer-modal
powinien być złożony z jakichś elementów składowych,
można też powiedzieć, że powinniśmy utworzyć szablon HTML, aby nadać elementowi jakieś cechy,
bo w przeciwnym razie będzie on jedynie pustym kontenerem.
Niemal wszystkie przeglądarki poza Internet Explorerem obsługują stosunkowo nowy znacznik <template>. Kod umieszczony w tym znaczniku nie jest renderowany, a jego zawartość można sklonować i wstawić do innego elementu. Użyjemy znacznika template, aby utworzyć zawartość naszego elementu.
Oto jak będzie wyglądać kod głównego pliku polymer-modal.html:
<link rel="import" href="../polymer/polymer-element.html">
<link rel="import" href="style.html">
<dom-module id="polymer-modal">
<template>
<style include="polymer-modal-style"></style>
<div class="modal">
<button type="button" class="modal__close">
<slot name="close-label">X</slot>
</button>
<div class="modal__heading">
<slot name="title"></slot>
</div>
<div class="modal__content">
<slot name="content"></slot>
</div>
</div>
</template>
<script src="polymer-modal.js"></script>
</dom-module>
Rzeczą, która od razu rzuca się w oczy, są dwa importy u góry pliku. Pierwszy z nich (polymer-element.html)
jest konieczny, abyśmy mogli utworzyć „Polymerowy” Custom Element. W drugim imporcie importujemy style elementu,
będąc przy stylach, od razu zwrócę uwagę, że oprócz importu, trzeba umieścić znacznik style
ze specjalnym atrybutem include
.
W Polymerze kod komponentu umieszczamy wewnątrz znacznika dom-module
,
znacznik ten posiada atrybut id
, który musi być identyczny z nazwą tworzonego elementu.
W środku dom-module
koniecznie musi znaleźć się szablon oraz skrypt. W skrypcie będzie umieszczona
definicja klasy elementu (mój skrypt jest wydzielony do osobnego pliku).
W szablonie umieściłem trzy elementy <slot>, powinniście to skojarzyć z atrybutem slot, o którym pisałem w rozdziale Robimy Custom Element. Ten element jest bardzo przydatny, dzięki niemu inne elementy, które zostały oznaczone atrybutem slot, są wstawiane do odpowiadających im slotów na podstawie atrybutu name. Za sprawą tej właściwości elementy tj. nagłówek, treść i etykieta przycisku, będą umieszczone w odpowiednim miejscu.
Klasa elementu
Aby nasz modal mógł działać, musimy napisać klasę, która dziedziczy
po Polymer.Element
. Poniżej został umieszczony kod pliku polymer-modal.js.
class PolymerModalElement extends Polymer.Element {
static get is() {
return 'polymer-modal';
}
static get properties() {
return {
opened: {
type: Boolean,
value: false,
reflectToAttribute: true
},
};
}
}
window.customElements.define(PolymerModalElement.is, PolymerModalElement);
Klasa może mieć dowolną nazwę. Ja swoją nazwałem PolymerModalElement
, a wewnątrz niej utworzyłem dwie metody
statyczne. Pierwsza z nich, czyli metoda is
jest konieczna i musi zwracać nazwę elementu.
Druga metoda properties
służy do definiowania atrybutów elementu.
Nasz przykładowy modal będzie najprostszym z możliwych i jedyne co będzie umieć to się otworzyć i zamknąć.
Z tej właśnie przyczyny utworzyłem w nim tylko atrybut o nazwie opened
, który jest typu Boolean.
Zostanie on użyty do zmiany widoczności elementu.
Style elementu
Okno modalne posiada już szablon i właściwość opened
, która mówi nam, czy jest one otwarte.
W związku z tym posiadamy już wszystko, co jest potrzebne do nadania stylów.
<dom-module id="polymer-modal-style">
<template>
<style>
:host {
--modal-width: 400px;
--modal-background: #fff;
--modal-padding: 10px;
--modal-border: 1px solid #000;
display: none;
}
:host([opened]) {
position: fixed;
top: 0;
left: 0;
display: flex;
width: 100vw;
height: 100vh;
overflow-y: auto;
overflow-x: hidden;
justify-content: center;
align-items: center;
}
.modal {
position: relative;
top: 0;
left: 0;
width: var(--modal-width);
background: var(--modal-background);
padding: var(--modal-padding);
border: var(--modal-border);
}
.modal__heading {
border-bottom: var(--modal-border);
}
.modal__close {
position: absolute;
top: var(--modal-padding);
right: var(--modal-padding);
}
</style>
</template>
</dom-module>
Podobnie jak w przypadku szablonu, także i tutaj kod został umieszczony w znaczniku dom-module
.
W zasadzie nie ma co tutaj komentować poza dwiema rzeczami.
Po pierwsze, został użyty selektor :host
,
który służy do nadawania stylów najwyższemu elementowi Shadow DOM, czyli Shadow Rootowi. Jak widać, zostało
tutaj zastosowane proste rozwiązanie, które polega na tym, że element jest widoczny tylko wtedy, gdy posiada
atrybut opened
.
Po drugie, zostały użyte zmienne CSS, których mógłbym nie dodawać, lecz wtedy
zablokowałbym możliwość stylowania elementów uwięzionych w Shadow DOM. Te zmienne można nadpisać z poziomu
odrębnego arkusza stylów.
Przycisk zamykania
Czyżbym o czymś zapomniał? Tak, okno powinno się zamykać po naciśnięciu przycisku. Wróćmy na moment do pliku polymer-modal.js i go zmodyfikujmy.
class PolymerModalElement extends Polymer.Element {
static get is() {
return 'polymer-modal';
}
static get properties() {
return {
opened: {
type: Boolean,
value: false,
reflectToAttribute: true
},
};
}
ready() {
super.ready();
this.shadowRoot.querySelector('.modal__close').addEventListener('click', () => {
this.opened = false;
});
}
}
window.customElements.define(PolymerModalElement.is, PolymerModalElement);
Jak widać, utworzyłem blok metody ready, w którym dodałem listenera do elementu .modal__close
.
Po naciśnięciu przycisku, do właściwości opened jest przypisywana wartość false, co powoduje zamknięcie się okna.
A jak otworzyć okno? Wystarczy ustawić elementowi atrybut opened.
Podsumowanie
Pokazałem jak zrobić proste okno modalne za pomocą komponentu webowego. To jednak nie wyczerpuje tematu, dlatego w kolejnych wpisach spróbuję pokazać bardziej zaawansowane techniki.