您可以混用 Apps Script 程式碼和 HTML,以最低成本產生動態網頁 如果您使用了混用程式碼和 HTML 的範本語言,例如 PHP、ASP 或 JSP,應該對語法感到熟悉。
指令碼小程式
Apps Script 範本可包含三個稱為 Scriptlet 的特殊標記。內部實景 使用 Scriptlet,您可以撰寫任何適用於一般 Apps Script 的程式碼 file:Scriptlet 可呼叫其他程式碼檔案中定義的函式、參照 全域變數或使用任何 Apps Script API。您甚至可以 請注意,這些函式和變數 程式碼檔案或其他範本中定義的函式所呼叫的函式。
將下例貼到指令碼編輯器中,
<?= ... ?>
標記 (列印 Scriptlet) 會顯示在
斜體。這種斜體程式碼會在網頁放送之前在伺服器上執行
因為 Scriptlet 程式碼會在網頁顯示前執行
每個網頁只能執行一次;與用戶端 JavaScript 或 Apps Script 不同
可讓您呼叫
google.script.run
,指令碼小程式無法
於頁面載入後再次執行。
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>
請注意,範本式 HTML 的 doGet()
函式與範例不同
瞭解如何建立和提供基本 HTML。函式
這裡會顯示一個
來自 HTML 的 HtmlTemplate
物件
檔案,
evaluate()
方法,即可
執行 Scriptlet 並將範本轉換為
HtmlOutput
物件,用來執行指令碼
向使用者放送
標準腳本
標準指令碼程式使用 <? ... ?>
語法,可在不載入程式碼的情況下執行程式碼
明確輸出內容。不過,在這個例子中
指令碼中的程式碼 結果 仍然可以影響 HTML 內容。
腳本以外的地方:
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>
列印腳本
列印指令碼程式 (使用 <?= ... ?>
語法) 會輸出
透過情境逸出將程式碼加入網頁中。
內容逸出是指 Apps Script 持續追蹤輸出內容的脈絡。
網頁 - HTML 屬性中、用戶端 script
標記內,或
其他任何位置 — 並且自動添加逸出字元
防範跨網站指令碼攻擊 (XSS) 攻擊。
在此範例中,第一個列印 Scriptlet 會直接輸出字串;是 後面是標準指令碼,可以設定陣列和迴圈,後面接著 另一個列印指令碼程式來輸出陣列內容。
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>
請注意,列印腳本只會輸出其中第一個陳述式的值;
其餘陳述的行為就像是包含在標準中
指令碼小程式。舉例來說,指令碼小程式 <?= 'Hello, world!'; 'abc' ?>
會顯示「Hello, world!」。
強制列印腳本
使用 <?!= ... ?>
語法的強制列印指令碼程式,就像列印一樣
使用腳本,但可以避免上下文逸出。
如果您的指令碼允許不信任的使用者輸入,內容逸出很重要。變更者: 相反地,如果腳本集輸出 就是要強制列印 包含您想依指定方式插入的 HTML 或指令碼。
一般而言,請使用列印腳本,而不要使用強制列印指令碼 除非您確定需要列印 HTML 或 JavaScript。
使用 Scriptlet 中的 Apps Script 程式碼
Scriptlet 不限於執行一般 JavaScript你也可以使用 使用下列三種技巧,讓您的範本存取 Apps Script 資料。
不過請注意,由於範本程式碼會在網頁提供前執行
這些技術只能將初始內容提供給網頁。使用方式
從網頁互動,使用 Apps Script 資料
google.script.run
API。
從範本呼叫 Apps Script 函式
Scriptlet 可以呼叫 Apps Script 程式碼檔案或程式庫中定義的任何函式。 本範例顯示將試算表資料提取至範本的一種方法, 根據資料建立 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>
直接呼叫 Apps Script API
你也可以直接在 Scriptlet 中使用 Apps Script 程式碼。本例 透過在 而非透過獨立的函式
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>
將變數推送至範本
最後,您可以將變數指派為屬性,將其推送至範本中
HtmlTemplate
物件的結構。一次
這個例子會再次完成與上述範例相同的結果。
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>
偵錯範本
範本可能難以偵錯,因為您編寫的程式碼並未執行 ;伺服器會將範本轉換為程式碼 這會產生程式碼
如果無法分辨範本如何解讀腳本
的偵錯方法
HtmlTemplate
類別可助你一臂之力
瞭解實際情況
getCode()
getCode()
會傳回
字串,包含伺服器從範本建立的程式碼。如果發生以下情況:
記錄
貼到指令碼編輯器中
照常進行偵錯
Apps Script 程式碼。
這個簡單的範本會再次顯示 Google 產品清單
後面接著 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>
記錄 (評估)
(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()
與 getCode()
類似,但會傳回已評估的程式碼做為註解
會與原始範本並排顯示
逐步瞭解已評估的程式碼
在任一已評估的程式碼範例中,最先看到的就是隱含
由 HtmlService.initTemplate()
方法建立的 output
物件。這個方法
因為只有範本本身需要使用,所以未記錄下來。output
是
一個特殊的 HtmlOutput
物件,當中有兩個
_
和 _$
等不常見名稱的屬性,可用於呼叫
append()
和
appendUntrusted()
。
output
還有 1 個特殊屬性 $out
,指的是一般
HtmlOutput
物件,沒有這些特殊屬性。範本
會在程式碼結尾傳回該一般物件
現在您已瞭解這個語法,程式碼的其餘部分應會變得相當簡單
以便追蹤。附加腳本以外的 HTML 內容 (例如 b
標記)
使用 output._ =
(不情境逸出)、
和 Scriptlet 會以 JavaScript 形式附加 (無論是否有內容逸出
視指令碼程式類型而定)。
請注意,經過評估的程式碼會保留範本中的行數。如果發生以下情況: 執行經評估的程式碼時發生錯誤,該行程式碼會對應至 範本中的對等內容
註解階層
評估的程式碼會保留行數,因此可用於註解 使用 Scriptlet 加入註解,以便排除其他 Scriptlet,甚至是 HTML 程式碼。這些 以下列舉幾個令人驚訝的評語:
<? 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. */ ?>