Wspomnieliśmy już trochę czym są Web Components, czas przejść do szczegółów i spróbować wykorzystać nowe możliwości przeglądarek. W części poświęconej AngularJS stworzyliśmy dyrektywę wprowadzającą element
<play-button src="...">
, teraz, krok po kroku, przerobimy tę dyrektywę na komponent.
Templates
Szablony są obojętne dla dokumentu, oznacza to, że nie zostaną pobrane zasoby z nim związane, aż do momentu użycia. Pozwalają również na zredukowanie ilości przesyłanego do klienta HTMLa, ponieważ dopiero po jego stronie zamienimy szablon na wiele elementów.
CAT_NAME
Czego wynikiem byłby dokument z trzema kotami i co najważniejsze images/CAT_NAME.png
nie zostanie nigdy pobrany.
Zadanie dla Ciebie:
- W
index.html
dodaj<template>
i umieść w nim szablon dyrektywyplayButton
- Zmodyfikuj dyrektywę
playButton
tak, żeby korzystała z dodanego<template>
- Pytania?
HTML Imports
HTML Imports pozwalają na zamknięcie plików potrzebnych do załadowania komponentu bądź bilbioteki wewnątrz jednego pliku, który będzie zawierać ich ścieżki. Poprawia to czytelność oraz pozwala wygodnie zgrupować powiązane ze sobą linki.
Należy pamiętać, że każda deklaracja importu zostanie pobrana do oddzielnego dokumentu w celu uniknięcia konfliktów z głównym dokumentem.
Przy wykonywaniu importów możemy również użyć atrybutu znanego z taga <script>
, a mianowicie async, który zachowa się analogicznie jak podczas użycia w dołączaniu skryptów.
Przykładowy import, który możemy użyć w pliku index.html w celu zagregowania struktury.
Natomiast wewnątrz pliku components/component-time-ago.html
umieścić:
Takie rozwiązanie pozwoli nam mieć pewność, że zanim stworzymy nasz komponent którego treść znajduje się wewnątrz ./time-ago/index.html
, będziemy mieć załadowaną bibliotekę Polymera oraz przykładowy komponent base.html
, po którym będzie dziedziczyć nasz time-ago
.
Jeżeli w obrębie jednego dokumentu wywołamy wewnątrz kilku importów ten sam link, zostanie on pobrany tylko za pierwszym razem. W ten sposób zapobiegniemy dublowaniu dołączania źródeł.
Zadanie dla Ciebie:
- Przenieś stworzony
<template>
, z którego korzysta dyrektywaplayButton
, do oddzielnego plikuwebcomponents/play-button/play-button.html
- Przenieś style wykorzystywane przez
playButton
dowebcomponents/play-button/play-button.css
i załącz style wewnątrzwebcomponents/play-button/play-button.html
- Przywróć działanie dyrektywy
playButton
- Pytania?
HTML imports a
document.querySelector()
Element
<link>
nie dodaje zawartości importowanego dokumentu bezpośrednio do aktualnego. Tworzy zagnieżdżony dokument, którego zawartość jest niewidoczna dla funkcji przeszukujących DOM, takich jakdocument.querySelector()
.Aby operować na zaimportowanym dokumencie należy wykorzystać atrybut
HTMLLinkElement.import
.link = document.querySelector 'link[rel=import]' heart = link.import # Access DOM of the document in /imports/heart.html pulse = heart.querySelector 'div.pulse' var link = document.querySelector('link[rel=import]'); var heart = link.import; // Access DOM of the document in /imports/heart.html var pulse = heart.querySelector('div.pulse');
Custom Elements
Tworzenie custom elementu odbywa się przez wywołanie funkcji document.registerElement, posiada ona dwa argumenty:
- String zawierający tag, który chcemy stworzyć (musi zawierać ’-‘ w nazwie w celu kompatybilności)
- Prototyp elementu HTML po którym nasz element będzie dziedziczył. Nie jest obowiązkowy, w przypadku jeśli go nie podamy, zostanie prototypem HTMLElement.
Tworząc prototyp możemy zadeklarować funkcje których działanie jest uzależnione od lifecycle’u elementu, możemy użyć następujących callbacków:
createdCallback
- odpalany w momencie stworzenia instancji komponentuattachedCallback
- odpalany w momencie dołączenia komponentu do DOMudetachedCallback
- odpalany w momencie odłączenia komponentu od DOMuattributeChangedCallback(attrName, oldVal, newVal)
- odpalany gdy zmieni się wartość atrybutu
Zadanie dla Ciebie
- Zaimplementuj
<play-button>
za pomocą Custom Elements- Usuń dyrektywę
playButton
- Pytania?
document.currentScript
W ramach HTML Imports został dodany property
document.currentScript
, który przechowuje referencję do elementu<script>
, który spowodował uruchomienie danego kodu JavaScript.Dla przeglądarek, które nie wspierają natywnie
document.currentScript
, webcomponents.js dostarcza polyfilldocument._currentScript
.Dzięki temu, w łatwy sposób możemy zlokalizować szablon naszego komponentu:
Hello World! # hello-world.coffee ownerDocument = document._currentScript.ownerDocument template = ownerDocument.querySelector 'template' class HelloWorld extends HTMLElement createdCallback: -> clone = document.importNode template.content, true this.appendChild clone document.registerElement 'hello-world', HelloWorld // hello-world.js var ownerDocument = document._currentScript.ownerDocument; var template = ownerDocument.querySelector('template'); function HelloWorld() {} HelloWorld.prototype = Object.create(HTMLElement.prototype); HelloWorld.prototype.createdCallback = function() { clone = document.importNode(template.content, true); this.appendChild(clone); }; document.registerElement('hello-world', HelloWorld);
Shadow DOM
Shadow DOM składa się z:
- hosta - czyli elementu na którym wołamy createShadowRoot(), jest to ostatni element dotyczący komponentu dostępny w dokumencie.
- roota - element który zwraca funkcja createShadowRoot(), jest to pierwszy element wewnątrz enkapsulacji
- boundary - “bariera” stworzona pomiędzy hostem a rootem, chroni style oraz skrypty przed wyciekaniem w obie strony
- insertion point - miejsce, które pozwala na przekazanie danych poprzez boundary, zazwyczaj atrybuty bądź treść elementu hosta, które są dostępne jako element
<content>
po stronie roota.
Czego efektem będzie:
Light DOM
Shadow DOM
Co najważniejsze styl zdefiniowany wewnątrz shadow DOM p { color: red; }
nie wpływa na wszystkie paragrafy w dokumencie.
Zadanie dla Ciebie:
- Zmodyfikuj element
play-button
, żeby korzystał z Shadow DOM- Przenieś style wykorzystywane przez
play-button
do wewnątrz jego szablonu modyfikując odpowiednio reguły- Pytania?
HTMLElement.shadowRoot
Shadow root stworzony metodą
HTMLElement.createShadowRoot()
jest także dostępny pod atrybutemHTMLElement.shadowRoot
.
link
Element
link
jest ignorowany wewnątrz Shadow DOM, więc do załączenia styli z zewnętrznego pliku, trzeba użyć@import
.