Możesz łączyć kod Apps Script z HTML-em, aby tworzyć dynamiczne strony przy minimalnym wysiłku. Jeśli używasz języka szablonów, który łączy kod i HTML, np. PHP, ASP lub JSP, składnia powinna być Ci znana.
Skrypty
Szablony Apps Script mogą zawierać 3 tagi specjalne, zwane skryptletami. W skrypcie możesz napisać dowolny kod, który działałby 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 poniższy przykład do edytora skryptów, zawartość tagu
<?= ... ?>
(skrypt drukowania) pojawi się w formie kursywy. Ten kod zapisany kursywą jest wykonywany 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 wywoływanych za pomocą google.script.run
skryptlety nie mogą być wykonywane ponownie po wczytaniu 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 podstawowego kodu 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 will always be served!</p>
<? } else { ?>
<p>This will never be served.</p>
<? } ?>
</body>
</html>
Drukowanie skryptów
Skrypty drukowania, które używają składni <?= ... ?>
, wyświetlają wyniki kodu na stronie za pomocą ucieczki kontekstowej.
Ucieczka kontekstowa oznacza, że Apps Script śledzi kontekst wyjścia na stronie – w atrybucie HTML, w tagu script
po stronie klienta lub w dowolnym innym miejscu – i automatycznie dodaje znaki ucieczki, aby chronić 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 skryplecie. 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 wprowadzanie danych przez niezaufanych użytkowników. Z kolei drukowanie wymuszone jest potrzebne, jeśli dane wyjściowe skryptu celowo zawierają 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 wymuszających drukowanie, 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, zanim strona zostanie wyświetlona 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średnie wywoływanie interfejsów Apps Script API
Możesz też używać kodu Apps Script bezpośrednio w skryptach. Ten przykład daje taki sam rezultat jak poprzedni, ponieważ 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>
Przekazywanie 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.
getCode()
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 prosty szablon, który ponownie wyświetla listę usług Google, a następnie wynik działania funkcji 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('');
})();
getCodeWithComments()
getCodeWithComments()
działa podobnie do funkcji getCode()
, ale zwraca oceniony kod w postaci komentarzy, które
pojawiają się obok oryginalnego szablonu.
Przeglądanie ocenionego kodu
Pierwszą rzeczą, jaką zauważysz w obu próbkach 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ę, reszta kodu powinna być dość łatwa do zrozumienia. Treści HTML poza skryptami (np. tag b
) są dołączane za pomocą tagu output._ =
(bez kontekstowego usuwania znaków specjalnych), a skrypty są dołączane jako JavaScript (z kontekstowym usuwaniem znaków specjalnych lub bez niego, w zależności od typu skryptu).
Pamiętaj, że oceniany kod zachowuje numery wierszy z szablonu. Jeśli podczas uruchamiania ocenionego kodu 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ą wykomentowywać 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 will print 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. */ ?>