Wypisywanie: innerHTML, innerText, outerHTML, outerText
W JavaScript istnieje kilka sposobów na wypisywanie tekstów (np. wyników obliczeń lub tekstowych podsumowań działania logiki skryptu). Czasem też chcemy obudować takie wypisywane rezultaty otrzymane w JS kodem HTML (np. umieścić w akapicie, w liście wypunktowanej albo w tabeli). Poznamy więc teraz cztery popularne właściwości: innerText
, textContent
, innerHTML
oraz outerHTML
. Są to oczywiście właściwości elementów blokowych, w których zazwyczaj umieszczamy wyniki działania skryptu – na przykład w przygotowanym uprzednio, a domyślnie pustym kontenerze typu: <div class="wyniki"></div>
czy <p class="wyniki"></p>
.
Wydawać się to może trywialne, bo w 90% przypadków ludzie na egzaminie korzystają z innerHTML
, lecz czy na pewno dobrze znamy wszystkie cztery właściwości i różnice pomiędzy nimi? A co, jeśli arkusz wymusi na nas użycie innej właściwości? Poznajmy zatem każdą z nich!
Dostęp do tekstu wewnątrz – innerText
Po pierwsze – gwoli formalności przypomnijmy, iż z użyciem JS możemy swobodnie manipulować (zarówno zmienić, jak i odczytać) pierwotnie istniejącą, zdefiniowaną w dokumencie HTML zawartością znaczników – może to być akapit, div, nagłówek itd.
Załóżmy więc, że istnieje na stronie np. nagłówek <h2>
:
<h2 class="tytul">Wylosuję dla Ciebie liczbę z przedziału od 1 do 100!</h2> <button onclick="losujLiczbe()">Wylosuj dla mnie liczbę</button>
I w zadaniu egzaminacyjnym wymaga się od nas, żeby po kliknięciu przycisku ten nagłówek zmienił treść (zgodnie z obietnicą zawartą w jego treści) na faktyczną liczbę wylosowaną z zadanego przedziału 1..100. Aby to zrobić najprościej, możemy w JS użyć właściwości innerText
(ang. inner = wewnętrzny, w środku):
function losujLiczbe() { // Pobieramy nagłówek na podstawie klasy CSS (stąd kropka) var naglowek = document.querySelector(".tytul"); // Losujemy liczbę z przedziału 1–100 (obiekt Math) var losowa = Math.floor(Math.random() * 100) + 1; // Podmieniamy tekst nagłówka na wylosowaną liczbę naglowek.innerText = "Twoja liczba to: " + losowa + ". Jeszcze raz?"; }
Jednak najważniejszym ograniczeniem właściwości innerText
jest fakt, iż nie pozwala na interpretację HTML, to znaczy nie możemy obudować wypisywanej treści znacznikami HTML. Rozważmy dodanie do wypisanej liczby jej podkreślenia:
function losujLiczbe() { // Pobieramy nagłówek na podstawie klasy CSS (stąd kropka) var naglowek = document.querySelector(".tytul"); // Losujemy liczbę z przedziału 1–100 (obiekt Math) var losowa = Math.floor(Math.random() * 100) + 1; // Podmieniamy tekst nagłówka na wylosowaną liczbę naglowek.innerText = "Twoja liczba to: <u>" + losowa + "</u>. Jeszcze raz?"; }
Rezultat w przeglądarce (oczywiście dla akurat tej wylosowanej liczby) będzie taki:
Twoja liczba to: <u>45</u>. Jeszcze raz?
Jak widzimy przeglądarka nie interpretuje znacznika <u>
tylko pokazuje go jako tekst. I właśnie dlatego istnieje także właściwość innerHTML
poprawnie obsługująca tagi, którą teraz się zajmijmy.
Tekst, lecz z działającymi tagami – innerHTML
Jeśli zatem chcemy z użyciem JS wygenerować nie tylko tekst, ale także obudować go znacznikami HTML, to zamiast innerText
użyjemy właściwości innerHTML
. Dla tego samego zadania co powyżej, kod JS będzie następujący:
function losujLiczbe() { // Pobieramy nagłówek na podstawie klasy CSS (stąd kropka) var naglowek = document.querySelector(".tytul"); // Losujemy liczbę z przedziału 1–100 (obiekt Math) var losowa = Math.floor(Math.random() * 100) + 1; // Podmieniamy tekst nagłówka na wylosowaną liczbę naglowek.innerHTML = "Twoja liczba to: <u>" + losowa + "</u>. Jeszcze raz?"; }
Teraz rezultat w przeglądarce będzie już zgodny z naszą intencją podkreślenia liczby:
Twoja liczba to: 45. Jeszcze raz?
Tym razem tagi HTML są już interpretowane przez przeglądarkę, a nie pokazywane jako tekst. Koniecznie też zwróćmy uwagę na zapis właściwości w JS – jest to innerHTML
, a nie często zapisywany błędnie: innerHtml
– wydawać się to może trywialne, ale to popularna pomyłka!
W tym miejscu wiele osób zapyta o to, po co w ogóle istnieje właściwość innerText
, skoro innerHTML
również umożliwia wypisywanie tekstów, a dodatkowo pozwala (jeśli chcemy) używać znaczników? Oczywiście w grę wchodzi tutaj przede wszystkim kontekst bezpieczeństwa (możliwość używania tagów niesie ze sobą ryzyko), lecz pełną odpowiedź na to pytanie najlepiej przedstawić w postaci tabelarycznej:
Opis potencjalnego działania | innerText | innerHTML |
---|---|---|
Przekazuje tekst do elementu HTML | Tak | Tak |
Pozwala również na tagi HTML w tekście | Nie | Tak |
Usuwanie potencjalnych niebezpiecznych tagów, czyli tzw. sanityzacja kodu) | Tak, bo nie obsługujemy tagów, pokazując znaczniki jako zwykły tekst | Nie, bo pozwoli “wykonać” wiele znaczników w przeglądarce |
Szybkość przetworzenia (bo uwzględniamy styl, widoczność) | Nieco wolniejsze | Nieco szybsze |
Wiele osób najczęściej używa na egzaminie właśnie właściwości innerHTML
do wypisywania tekstów i to nawet jeśli ten tekst nie zawiera znaczników. Raczej nie jest to błąd, a sytuacja typu overkill (ang. przesada), lecz my rozważmy użycie innerText
wszędzie tam, gdzie znaczniki nie są potrzebne. W końcu nie zawsze potrzebujemy wszechstronności – czasem zależy nam najbardziej na bezpieczeństwie i prostocie zapisu.
Alternatywny dostęp do tekstu – textContent
Właściwość textContent
jest podobna do innerText
, natomiast różnica polegała na tym, iż umożliwiała nam ona odczytanie lub ustawienie tekstu w elemencie nie przejmując się widocznością tego kontenera, zdefiniowaną w CSS. Czyli podczas używania textContent
przeglądarka nie analizowała, czy coś jest aktualnie widoczne na stronie (ustawiona właściwość CSS display:none
ukrywa przecież obiekt), co jak najbardziej było uwzględniane przy użyciu innerText
.
A zatem próba odczytania tekstu z ukrytego akapitu poprzez innerText
zakończyłaby się niepowodzeniem – w poniższym skrypcie otrzymalibyśmy pustą wartość w drugim alercie:
<style> .napis { display:none; } </style> <p class="napis">Tajemnicza, ukryta na stronie treść akapitu.</p> <button onclick="pokazZawartosc()">Odczytaj niewidoczną treść</button> <script> function pokazZawartosc() { var akapit = document.querySelector(".napis"); alert(akapit.textContent); alert(akapit.innerText); } </script>
Dlaczego jednak cały czas mówimy o tym w czasie przeszłym? Ponieważ współczesne przeglądarki (np. Google Chrome, Firefox) zaktualizowały sposób działania innerText
ujednolicając ich zachowanie – oba alerty zwrócą zawartość akapitu. Ta drobna różnica w działaniu obu sposobów jest więc dziś nieaktualna, lecz oczywiście właściwość textContent
wciąż pozostaje jak najbardziej działającą alternatywą dla innerText
i możemy jej bezproblemowo także używać.
Właściwość outerHTML – dostęp także do elementu
Kolejna właściwość, czyli outerHTML
(ang. outer = zewnętrzny) pozwala na dostęp (odczyt, zapis) do całego elementu, a nie tylko jego zawartości! Rozważmy więc w poniższym przykładzie zmianę także samego znacznika, a nie samej jego wewnętrznej zawartości:
<p id="tekst">To jest paragraf.</p> <button onclick="zmienOuterHTML()">Zmień także rodzaj znacznika</button>
function zmienOuterHTML() { var tekst = document.getElementById("tekst"); tekst.outerHTML = "<h2>Czary mary - teraz to nagłówek!</h2>"; }
I tak oto akapit <p>
został podmieniony w przeglądarce w JS na nagłówek <h2>
. Zależnie od arkusza z zadaniem, czasami może się to okazać przydatne na egzaminie INF.03 oraz oczywiście także w praktyce tworzenia realnych stron internetowych, zależnie od naszych intencji.
Interpolacje podczas wypisywania
W JavaScript bardzo często chcemy wypisać wartość jakiejś zmiennej razem z tekstem. Na przykład: użytkownik podał imię, a my chcemy napisać: Witaj, Janek!
albo Podano liczbę: 42
. Właśnie w takich sytuacjach do gry wchodzi tzw. interpolacja łańcuchów znaków – czyli sposób łączenia tekstu z wartością zmiennej – najlepiej gdyby był czytelny, nowoczesny i wygodny.
Klasyczny sposób w JS to oczywiście używany także w tej lekcji operator konkatenacji +
:
let imie = "Kasia"; console.log("Witaj, " + imie + "!");
Zapis działający i w zupełności wystarczający do egzaminu. Natomiast stanie się on mniej nieczytelny, gdy chcemy wstawić do łańcuch kilka zmiennych lub dłuższy tekst. Cudzysłowy, plusy i spacje mieszają się – dla wielu osób łatwo się w tym miejscu pomylić. I dlatego warto poznać nowocześniejszy sposób – interpolację z użyciem zapisu ${zmienna}
:
let imie = "Kasia"; console.log(`Witaj, ${imie}!`);
Są to tzw. “szablony tekstowe” (ang. template strings), jak widać zapisane w tzw. backticks (czyli apostrofach typu `
, które wstawiamy na klawiaturze za pomocą klawisza tyldy – pod Escape). Dzięki takiemu zapisowi zdania wyglądają podobnie jak w języku naturalnym – nie ma tylu spójników – jest to bardzo intuicyjne i czytelne.
Gdy chcemy wstawić kilka wartości – np. imię, nazwisko i wiek – to taki zapis z interpolacją stanie się już nie tylko czytelniejszy, ale także krótszy:
let imie = "Kasia"; let nazwisko = "Nowak"; let wiek = 18; // template strings console.log(`Użytkownik: ${imie} ${nazwisko}, wiek: ${wiek} lat`); // klasyczna konkatenacja - zapis dłuższy oraz łatwiej tu o literówkę! console.log("Użytkownik: " + imie + " " + nazwisko + ", wiek: " + wiek + " lat");
Porównanie czytelności i długości widać gołym okiem. Gdzie możemy używać zapisu ${zmienna} w template strings? W codziennych egzaminacyjnych sytuacjach – na przykład:
console.log(...)
– informacja w logach konsoli w Devtoolsalert(...)
– tekst w wyskakującym oknie typu alertinnerHTML = ...
– wyświetlanie tekstu w div czy akapicie na stronie- przekazywanie wartości np. adresów URL do zmiennych
Czego potrzebujemy, żeby to nowoczesne wypisywanie działało? Musimy pamiętać o dwóch rzeczach:
- Zamiast zwykłych cudzysłowów
"..."
lub apostrofów prostych'...'
używamy backticków – czyli:`...`
. - W środku zapisujemy zmienną w formacie:
${nazwaZmiennej}
Podsumowanie
Na koniec jeszcze jedna uwaga, konieczna w tym miejscu – zwróćmy uwagę, iż akapity, nagłówki czy divy i pojemniki semantyczne (article, section, header, footer, aside) faktycznie posiadają w JS cztery omówione przez nas w tej lekcji właściwości, natomiast co innego pola formularzy (inputy, textarea, przyciski) – aby dostać się do zawartości wewnątrz nich wykorzystujemy właściwość value
, czyli wartość w środku pola. Pomieszanie tych właściwości to stosunkowo częsta pomyłka.
Co na pewno warto zapamiętać?
innerText
– pozwala na dostęp do tekstu, podobnie jaktextContent
– dawniej co prawda istniała opisana przez nas różnica przy ustawieniu właściwościdisplay:none
w CSS dla elementu (obiektu) zdefiniowanego w HTML, jednak we współczesnych przeglądarkach działanie obu właściwości zostało ujednoliconeinnerHTML
– pozwala dodawać znaczniki HTML podczas wypisywania, co może być niebezpieczneouterHTML
– dając dostęp także do samego znacznika, pozwala nawet podmienić cały element (obiekt) na inny- Interpolacja łańcuchów, czyli zastosowanie “szablonów tekstowych” (ang. template strings), zapisanych w tzw. backticks
`
poprawia czytelność wypisywania, zwłaszcza dla wielu zmiennych, które normalnie trzeba by konkatenować operatorem+
:
// template strings console.log(`Użytkownik: ${imie} ${nazwisko}, wiek: ${wiek} lat`); // klasyczna konkatenacja - zapis dłuższy oraz łatwiej tu o literówkę! console.log("Użytkownik: " + imie + " " + nazwisko + ", wiek: " + wiek + " lat");