Możesz używać szablonów do łączenia kodu Google Apps Script i HTML, aby tworzyć dynamiczne strony przy minimalnym nakładzie pracy. Jeśli używasz języków szablonów, które łączą kod i HTML, takich jak PHP, ASP lub JSP, składnia powinna być Ci znana.
Scriptlety
Szablony Apps Script mogą zawierać 3 specjalne tagi zwane skryptletami. W skrypcie możesz pisać dowolny kod, który działa w normalnym pliku Apps Script: skrypty mogą wywoływać funkcje zdefiniowane w innych plikach kodu, odwoływać się do zmiennych globalnych lub korzystać z dowolnych interfejsów API Apps Script. W skryptach możesz nawet definiować funkcje i zmienne, ale nie mogą one być wywoływane przez funkcje zdefiniowane w plikach kodu ani w innych szablonach.
Jeśli wkleisz do edytora skryptów poniższy przykład, zawartość tagu <?= ... ?> (skrypt drukowania) pojawi się w formie kursywy. Ten kod jest uruchamiany na serwerze, zanim strona zostanie wyświetlona użytkownikowi. Kod skryptletu jest wykonywany przed wyświetleniem strony, więc może być uruchamiany tylko raz na stronę. W przeciwieństwie do funkcji JavaScript po stronie klienta lub funkcji Apps Script, które wywołujesz za pomocą google.script.run, skrypty nie mogą być ponownie wykonywane po załadowaniu strony.
Code.gs
function doGet() {
return HtmlService
.createTemplateFromFile('Index')
.evaluate();
}
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
Hello, World! The time is <?= new Date() ?>.
</body>
</html>
Pamiętaj, że funkcja doGet w przypadku szablonowego kodu HTML różni się od przykładów tworzenia i wyświetlania podstawowej wersji HTML. Funkcja pokazana poniżej generuje obiekt HtmlTemplate z pliku HTML, a następnie wywołuje jego metodę evaluate, aby wykonać skrypty i przekształcić szablon w obiekt HtmlOutput, który skrypt może udostępnić użytkownikowi.
Standardowe skrypty
Standardowe skrypty, które używają składni <? ... ?>, wykonują kod bez jawnego wyświetlania treści na stronie. Jak jednak pokazuje ten przykład, wynik kodu w skryplecie może nadal wpływać na zawartość HTML poza skryptem:
Code.gs
function doGet() {
return HtmlService
.createTemplateFromFile('Index')
.evaluate();
}
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<? if (true) { ?>
<p>This is always served!</p>
<? } else { ?>
<p>This is never served.</p>
<? } ?>
</body>
</html>
Drukowanie skryptów
Skrypty drukowania, które używają składni <?= ... ?>, wyświetlają wyniki kodu na stronie za pomocą kontekstowego wyjścia.
Ucieczka kontekstowa oznacza, że Apps Script śledzi kontekst danych wyjściowych na stronie – w atrybucie HTML, w tagu script po stronie klienta lub w dowolnym innym miejscu – i automatycznie dodaje znaki ucieczki w celu ochrony przed atakami typu cross-site scripting (XSS).
W tym przykładzie pierwszy skrypt drukowania bezpośrednio wyświetla ciąg znaków. Następnie znajduje się standardowy skrypt, który konfiguruje tablicę i pętlę, a po nim kolejny skrypt drukowania, który wyświetla zawartość tablicy.
Code.gs
function doGet() {
return HtmlService
.createTemplateFromFile('Index')
.evaluate();
}
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<?= 'My favorite Google products:' ?>
<? var data = ['Gmail', 'Docs', 'Android'];
for (var i = 0; i < data.length; i++) { ?>
<b><?= data[i] ?></b>
<? } ?>
</body>
</html>
Pamiętaj, że skryptlet drukowania wyświetla tylko wartość pierwszego wyrażenia. Pozostałe wyrażenia działają tak, jakby były zawarte w standardowym skrypcie. Na przykład skrypt <?= 'Hello, world!'; 'abc' ?> only
wyświetla tylko „Hello, world!”.
Wymuszanie drukowania skryptów
Skrypty wymuszające drukowanie, które używają składni <?!= ... ?>, działają podobnie jak skrypty drukowania, ale unikają ucieczki kontekstowej.
Ucieczka kontekstowa jest ważna, jeśli skrypt zezwala na dane wejściowe użytkownika z niezaufanych źródeł. Z kolei wymuszone drukowanie jest potrzebne, jeśli dane wyjściowe skryptu mają celowo zawierać kod HTML lub skrypty, które chcesz wstawić dokładnie tak, jak zostały określone.
Zasadniczo używaj skryptów drukowania zamiast skryptów wymuszonego drukowania, chyba że wiesz, że musisz wydrukować kod HTML lub JavaScript bez zmian.
Kod Apps Script w skryptletach
Skrypty nie są ograniczone do uruchamiania zwykłego JavaScriptu. Możesz też użyć jednej z tych 3 technik, aby umożliwić szablonom dostęp do danych Apps Script.
Pamiętaj jednak, że kod szablonu jest wykonywany przed wyświetleniem strony użytkownikowi, więc te techniki mogą tylko dostarczać początkową treść strony. Aby interaktywnie uzyskiwać dostęp do danych Apps Script ze strony, użyj interfejsu google.script.run API.
Wywoływanie funkcji Apps Script z szablonu
Skrypty mogą wywoływać dowolną funkcję zdefiniowaną w pliku kodu lub bibliotece Apps Script. Ten przykład pokazuje jeden ze sposobów pobierania danych z arkusza kalkulacyjnego do szablonu, a następnie tworzenia na ich podstawie tabeli HTML.
Code.gs
function doGet() {
return HtmlService
.createTemplateFromFile('Index')
.evaluate();
}
function getData() {
return SpreadsheetApp
.openById('1234567890abcdefghijklmnopqrstuvwxyz')
.getActiveSheet()
.getDataRange()
.getValues();
}
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<? var data = getData(); ?>
<table>
<? for (var i = 0; i < data.length; i++) { ?>
<tr>
<? for (var j = 0; j < data[i].length; j++) { ?>
<td><?= data[i][j] ?></td>
<? } ?>
</tr>
<? } ?>
</table>
</body>
</html>
bezpośrednio wywoływać interfejsy Apps Script API.
Możesz też używać kodu Apps Script bezpośrednio w skryptletach. Ten przykład daje ten sam rezultat co poprzedni, ale dane są wczytywane w samym szablonie, a nie za pomocą osobnej funkcji.
Code.gs
function doGet() {
return HtmlService
.createTemplateFromFile('Index')
.evaluate();
}
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<? var data = SpreadsheetApp
.openById('1234567890abcdefghijklmnopqrstuvwxyz')
.getActiveSheet()
.getDataRange()
.getValues(); ?>
<table>
<? for (var i = 0; i < data.length; i++) { ?>
<tr>
<? for (var j = 0; j < data[i].length; j++) { ?>
<td><?= data[i][j] ?></td>
<? } ?>
</tr>
<? } ?>
</table>
</body>
</html>
Przesyłanie zmiennych do szablonów
Na koniec możesz przekazywać zmienne do szablonu, przypisując je jako właściwości obiektu HtmlTemplate. Ten przykład ponownie daje taki sam wynik jak poprzednie.
Code.gs
function doGet() {
var t = HtmlService.createTemplateFromFile('Index');
t.data = SpreadsheetApp
.openById('1234567890abcdefghijklmnopqrstuvwxyz')
.getActiveSheet()
.getDataRange()
.getValues();
return t.evaluate();
}
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<table>
<? for (var i = 0; i < data.length; i++) { ?>
<tr>
<? for (var j = 0; j < data[i].length; j++) { ?>
<td><?= data[i][j] ?></td>
<? } ?>
</tr>
<? } ?>
</table>
</body>
</html>
Debugowanie szablonów
Debugowanie szablonów może być trudne, ponieważ pisany przez Ciebie kod nie jest wykonywany bezpośrednio. Zamiast tego serwer przekształca szablon w kod, a następnie go wykonuje.
Jeśli nie jest oczywiste, jak szablon interpretuje skrypty, możesz skorzystać z 2 metod debugowania w klasie HtmlTemplate, które pomogą Ci lepiej zrozumieć, co się dzieje.
Funkcja getCode
Funkcja getCode zwraca ciąg znaków zawierający kod, który serwer tworzy na podstawie szablonu.
Jeśli zalogujesz kod, a następnie wkleisz go do edytora skryptów, możesz go uruchomić i debugować jak zwykły kod Apps Script.
Oto szablon, który ponownie wyświetla listę usług Google, a następnie wynik działania getCode:
Code.gs
function myFunction() {
Logger.log(HtmlService
.createTemplateFromFile('Index')
.getCode());
}
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<?= 'My favorite Google products:' ?>
<? var data = ['Gmail', 'Docs', 'Android'];
for (var i = 0; i < data.length; i++) { ?>
<b><?= data[i] ?></b>
<? } ?>
</body>
</html>
LOG (EVALUATED)
(function() { var output = HtmlService.initTemplate(); output._ = '<!DOCTYPE html>\n';
output._ = '<html>\n' +
' <head>\n' +
' <base target=\"_top\">\n' +
' </head>\n' +
' <body>\n' +
' '; output._$ = 'My favorite Google products:' ;
output._ = ' '; var data = ['Gmail', 'Docs', 'Android'];
for (var i = 0; i < data.length; i++) { ;
output._ = ' <b>'; output._$ = data[i] ; output._ = '</b>\n';
output._ = ' '; } ;
output._ = ' </body>\n';
output._ = '</html>';
/* End of user code */
return output.$out.append('');
})();
Funkcja getCodeWithComments
Funkcja getCodeWithComments jest podobna do funkcji getCode(), ale zwraca obliczony kod jako komentarze, które pojawiają się obok oryginalnego szablonu.
Przeglądanie ocenionego kodu
Pierwszą rzeczą, jaką zauważysz w każdym przykładzie ocenianego kodu, jest niejawny obiekt output utworzony przez metodę HtmlService.initTemplate. Ta metoda nie jest udokumentowana, ponieważ tylko szablony muszą jej używać. output to specjalny obiekt HtmlOutput o 2 nietypowych właściwościach: _ i _$, które są skrótami wywołań append i appendUntrusted.
output ma jeszcze jedną właściwość specjalną, $out, która odnosi się do zwykłego obiektu HtmlOutput, który nie ma tych właściwości specjalnych. Szablon
zwraca ten zwykły obiekt na końcu kodu.
Teraz, gdy rozumiesz tę składnię, możesz przejść do pozostałej części kodu. Treść HTML poza skryptami (np. tag b) jest dołączana za pomocą funkcji output._ = (bez kontekstowego kodowania znaków specjalnych), a skrypty są dołączane jako JavaScript (z kontekstowym kodowaniem znaków specjalnych lub bez niego, w zależności od typu skryptu).
Oceniony kod zachowuje numery wierszy z szablonu. Jeśli podczas uruchamiania kodu poddanego ocenie wystąpi błąd, wiersz będzie odpowiadać równoważnej treści w szablonie.
Hierarchia komentarzy
Ponieważ oceniany kod zachowuje numery wierszy, komentarze w skryptach mogą komentować inne skrypty, a nawet kod HTML. Te przykłady pokazują kilka zaskakujących efektów komentarzy:
<? var x; // a comment ?> This sentence won't print because a comment begins
inside a scriptlet on the same line.
<? var y; // ?> <?= "This sentence won't print because a comment begins inside
a scriptlet on the same line.";
output.append("This sentence prints because it's on the next line, even though
it's in the same scriptlet.") ?>
<? doSomething(); /* ?>
This entire block is commented out,
even if you add a */ in the HTML
or in a <script> */ </script> tag,
<? until you end the comment inside a scriptlet. */ ?>