Dotkniemy teraz tematu, jakim są Custom Web Components a także dziedziczenia z wbudowanych typów. Napiszemy klasę będącą własną wersją tagu <a> o innej funkcjonalności.

Tworzymy custom anchor – dziedziczenie, connectedCallback

Nie tworzymy całkowicie nowego tagu HTML (to też da się zrobić, a może nawet przede wszystkim, za pomocą Web Components), ale własną wersję już istniejącego tagu. Nasz komponent od strony HTML będzie więc wykorzystywał swój normalny tag oraz atrybut „is”:

<a is="custom-anchor" href="#">Custom anchor</a>
<script src="./webcomponent.js"></script>

A oto podstawowy JavaScript do tworzenia komponentów rozszerzających działanie wbudowanych tagów:

class AnchorCustom extends HTMLAnchorElement {
    connectedCallback(){
        console.log('connected');
    }
}

customElements.define('custom-anchor', AnchorCustom, {extends: 'a'});

Słówko kluczowe extends służy do dziedziczenia w JavaScript. W define musimy je jeszcze potwierdzić (gdybyśmy tworzyli własny komponent, byłoby to zbędne zaś naszym tagiem byłby <custom-anchor>) podając odpowiednią nazwę tagu.

Metoda conntectedCallback działa w momencie, gdy element zostanie przypięty do strony. Jeżeli mamy trochę doświadczenia z frameworkami frontendowymi możemy się tego domyślić.

Teraz nasz tag <a> powinien działać jak normalny tag, ale wywołać console.loga po podłączeniu.

Coś prostego – confirm anchor

Zrobimy coś prostego – link, który nas pyta, czy aby na pewno chcemy wyjść ze strony. Oczywiście będziemy potrzebowali jakiegoś adresu, innego niż #, aby to sprawdzić:

<a is="custom-anchor" href="https://www.google.com">Custom anchor</a>

Nasza wariacja tagu <a> nadal nazywa się custom-anchor, ale nazwę klasy zamienimy na AnchorConfirm i sobie tę klasę szybciutko napiszemy:

class AnchorConfirm extends HTMLAnchorElement {
    connectedCallback(){
        this.addEventListener("click", function(e){
            if(!confirm("Do you want to leave this site?"))
                e.preventDefault();
        });
    }
}

customElements.define('custom-anchor', AnchorConfirm, {extends: 'a'});

W define pierwszy argument to nazwa tagu, lub w przypadku dziedziczenia z wbudowanych tagów nazwa wariacji, do której odwołujemy się przez atrybut is. Dalej nazwa klasy i potwierdzenie, z jakiego tagu dziedziczymy.

W normalnej obiektówce wystarczy extends i nazwa klasy, ale tutaj mamy do czynienia z Web Components API i pewne kroki są wymagane.

Dalej, connectedCallback podpina event listener, który wykorzystuje wbudowane (i całkowicie nieznane, słusznie zresztą) confirm API (jest jeszcze alert i prompt, w dawnych, słusznie minionych czasach te funkcje były nadużywane aż do przesady) i jeżeli nie potwierdzimy, że wyjść chcemy – preventDefault.

Pora napisać coś ciekawszego.

Scroll anchor – kotwica do elementu na stronie

Pokażę nasz HTML i już będziemy wiedzieli bez zbędnych wstępów co chcemy tutaj napisać, jeżeli tytuł nas wystarczająco nie naprowadził:

<a is="custom-anchor" href="#heading-two">Custom anchor</a>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<p id="heading-two">Lorem ipsum dolor sit amet consectetur adipisicing elit. Doloribus similique 
 harum doloremque eligendi veritatis nesciunt.</p>
<script src="./webcomponent.js"></script>

Wielokrotnie już to robiliśmy w różnych konfiguracjach i na różne sposoby, chodzi nam o smooth scroll za pomocą scrollIntoView. Na początek – zatrzymujemy domyślne działanie, którego nie chcemy:

class AnchorScroll extends HTMLAnchorElement {
    connectedCallback(){
        this.addEventListener("click", function(e){
            e.preventDefault();
        });
    }
}

Teraz pobieramy kotwicę i wykonujemy scrollIntoView:

class AnchorScroll extends HTMLAnchorElement {
    connectedCallback(){
        this.addEventListener("click", function(e){
            e.preventDefault();
            const anchor = this.getAttribute('href');
            document.querySelector(anchor).scrollIntoView({
                behavior: 'smooth'
            });
        });
    }
}

customElements.define('custom-anchor', AnchorScroll, {extends: 'a'});

Komponent gotowy do użycia i jak najbardziej działa. Poznaliśmy dziedziczenie w JS oraz zdobyliśmy podstawy Web Components API – to już coś!