คุณอาจใช้โค้ด Apps Script และ HTML ร่วมกันเพื่อสร้างหน้าแบบไดนามิกได้โดยใช้ความพยายามเพียงเล็กน้อย หากคุณใช้ภาษาเทมเพลตที่ผสมผสานโค้ดและ HTML เช่น PHP, ASP หรือ JSP ไวยากรณ์ควรคุ้นเคย
สคริปต์
เทมเพลต Apps Script จะมีแท็กพิเศษ 3 แท็กที่เรียกว่า Scriptlet ใน JavaScript ให้คุณเขียนโค้ดที่สามารถทํางานในไฟล์ Apps Script ปกติได้ ส่วน Scriptlet สามารถเรียกใช้ฟังก์ชันที่กําหนดไว้ในไฟล์โค้ดอื่นๆ อ้างอิงตัวแปรร่วม หรือใช้ Apps Script API ใดก็ได้ คุณยังกําหนดฟังก์ชันและตัวแปรภายในสคริปต์ได้ด้วย โดยมีข้อควรระวังว่าฟังก์ชันนี้เรียกใช้ได้ด้วยฟังก์ชันที่ระบุไว้ในไฟล์โค้ดหรือเทมเพลตอื่นๆ
หากวางตัวอย่างด้านล่างลงในเครื่องมือแก้ไขสคริปต์ เนื้อหาของแท็ก <?= ... ?>
(สคริปต์การพิมพ์) จะปรากฏเป็นตัวเอียง ซึ่งรหัสตัวเอียงจะทํางานอยู่บนเซิร์ฟเวอร์ก่อนแสดงหน้าเว็บต่อผู้ใช้ เนื่องจากโค้ดสคริปต์ทํางานก่อนที่หน้าเว็บจะแสดง โค้ดนี้จึงทํางานได้เพียง 1 ครั้งต่อหน้า ซึ่งต่างจากฟังก์ชัน JavaScript หรือ Apps Script ฝั่งไคลเอ็นต์ที่คุณเรียกใช้ผ่าน google.script.run
ส่วนสคริปต์จะทํางานไม่ได้หลังจากโหลดหน้าเว็บแล้ว
รหัส
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>
โปรดทราบว่าฟังก์ชัน doGet()
สําหรับ HTML ที่มีเทมเพลตแตกต่างจากตัวอย่างสําหรับการสร้างและการแสดงผล HTML พื้นฐาน ฟังก์ชันที่แสดงที่นี่จะสร้างออบเจ็กต์ HtmlTemplate
จากไฟล์ HTML จากนั้นเรียกใช้เมธอด evaluate()
เพื่อเรียกใช้สคริปต์และแปลงเทมเพลตเป็นออบเจ็กต์ HtmlOutput
ที่สคริปต์แสดงแก่ผู้ใช้ได้
สคริปต์มาตรฐาน
สคริปต์มาตรฐานซึ่งใช้ไวยากรณ์ <? ... ?>
จะเรียกใช้โค้ดโดยไม่ต้องเอาต์พุตเนื้อหาไปที่หน้าเว็บอย่างชัดแจ้ง อย่างไรก็ตาม ดังที่แสดงในตัวอย่างนี้ ผลลัพธ์ของโค้ดภายใน JavaScript จะยังคงส่งผลต่อเนื้อหา HTML นอกสคริปต์สคริปต์
รหัส
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>
การพิมพ์สคริปต์
การพิมพ์สคริปต์ขนาดเล็กที่ใช้ไวยากรณ์ <?= ... ?>
จะแสดงผลของโค้ดลงในหน้าเว็บโดยใช้การ Escape ตามบริบท
การ Escape ตามบริบทหมายความว่า Apps Script จะติดตามบริบทของเอาต์พุตบนหน้าเว็บ ในแอตทริบิวต์ HTML ในแท็ก script
ฝั่งไคลเอ็นต์ หรือที่อื่นๆ และเพิ่มอักขระหลีกโดยอัตโนมัติเพื่อป้องกันการโจมตีด้วย Cross-site Scripting (XSS)
ในตัวอย่างนี้ สคริปต์สคริปต์การพิมพ์แรกจะแสดงสตริงโดยตรง ตามด้วยสคริปต์สคริปต์มาตรฐานที่ตั้งค่าอาร์เรย์และวนซ้ํา ตามด้วยสคริปต์การพิมพ์อื่นๆ เพื่อเอาต์พุตเนื้อหาของอาร์เรย์
รหัส
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' ?>
จะพิมพ์ว่า "สวัสดีทั่วโลก" เท่านั้น
ตารางการพิมพ์ที่บังคับ
สคริปต์การพิมพ์ที่บังคับซึ่งใช้ไวยากรณ์ <?!= ... ?>
นั้นเหมือนกับการพิมพ์สคริปต์ ยกเว้นการหลบเลี่ยงบริบท
การใช้ Escape ตามบริบทเป็นสิ่งสําคัญหากสคริปต์ของคุณอนุญาตให้มีการป้อนข้อมูลผู้ใช้ที่ไม่น่าเชื่อถือ ในทางตรงกันข้าม คุณจะต้องบังคับให้พิมพ์หากเอาต์พุตของ Scriptlet มี Intent หรือ HTML ที่คุณต้องการแทรกให้ตรงตามที่ระบุทุกประการ
ตามกฎทั่วไป ให้ใช้สคริปต์การพิมพ์แทนการพิมพ์ฉบับพิมพ์ของสคริปต์ เว้นแต่คุณจะรู้ว่าต้องพิมพ์ HTML หรือ JavaScript โดยไม่มีการเปลี่ยนแปลง
รหัส Apps Script ใน Scriptlet
Scriptlet ไม่ได้จํากัดอยู่ที่การเรียกใช้ JavaScript ปกติเท่านั้น คุณยังสามารถใช้เทคนิค 3 อย่างต่อไปนี้เพื่อให้เทมเพลตเข้าถึงข้อมูล Apps Script ได้
อย่างไรก็ตาม โปรดทราบว่าเนื่องจากโค้ดเทมเพลตทํางานก่อนที่จะมีการแสดงหน้าเว็บต่อผู้ใช้ เทคนิคเหล่านี้จึงส่งได้เฉพาะเนื้อหาเริ่มต้นลงในหน้าเว็บเท่านั้น หากต้องการเข้าถึงข้อมูล Apps Script จากหน้าเป็นแบบอินเทอร์แอกทีฟ ให้ใช้ google.script.run
API แทน
การเรียกใช้ฟังก์ชัน Apps Script จากเทมเพลต
Scriptlet สามารถเรียกใช้ฟังก์ชันที่ระบุไว้ในไฟล์หรือไลบรารีโค้ด Apps Script ตัวอย่างนี้แสดงให้เห็นวิธีดึงข้อมูลจากสเปรดชีตไปยังเทมเพลต จากนั้นจึงสร้างตาราง HTML จากข้อมูล
รหัส
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 โดยตรง
คุณยังสามารถใช้โค้ด Apps Script ใน Scriptlet ได้โดยตรง ตัวอย่างนี้จะให้ผลลัพธ์เดียวกับตัวอย่างก่อนหน้าโดยการโหลดข้อมูลในเทมเพลตเอง ไม่ใช่ผ่านฟังก์ชันแยกต่างหาก
รหัส
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
ขอย้ําอีกครั้งว่าตัวอย่างนี้ได้รับผลลัพธ์เดียวกับตัวอย่างก่อนหน้านี้
รหัส
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>
เทมเพลตการแก้ไขข้อบกพร่อง
การแก้ไขข้อบกพร่องของเทมเพลตอาจทําได้ยากเนื่องจากโค้ดที่คุณเขียนไม่ได้ดําเนินการโดยตรง แต่เซิร์ฟเวอร์จะเปลี่ยนเทมเพลตของคุณให้เป็นโค้ดแล้วเรียกใช้โค้ดที่ได้
หากยังไม่แน่ใจว่าเทมเพลตตีความสคริปต์สคริปต์อย่างไร การแก้ไขข้อบกพร่อง 2 วิธีในชั้นเรียน HtmlTemplate
จะช่วยให้คุณเข้าใจสิ่งที่เกิดขึ้นได้ชัดเจนขึ้น
getCode()
getCode()
จะแสดงสตริงที่มีโค้ดที่เซิร์ฟเวอร์สร้างจากเทมเพลต หากบันทึกโค้ดแล้ววางโค้ดลงในโปรแกรมแก้ไขสคริปต์ คุณจะเรียกใช้โค้ดและแก้ไขข้อบกพร่องเหมือนโค้ด Apps Script ปกติได้
ต่อไปนี้คือเทมเพลตง่ายๆ ที่แสดงรายการผลิตภัณฑ์ของ Google อีกครั้ง ตามด้วยผลการค้นหาของ getCode()
รหัส
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('');
})();
getCodeWithความคิดเห็น()
getCodeWithComments()
คล้ายกับ getCode()
แต่แสดงผลโค้ดที่ประเมินเป็นความคิดเห็นที่ปรากฏข้างเทมเพลตเดิม
โค้ดที่ประเมินคําแนะนําแบบทีละขั้น
สิ่งแรกที่คุณจะเห็นในตัวอย่างโค้ดที่ประเมินคือออบเจ็กต์ output
โดยนัยที่เมธอด HtmlService.initTemplate()
สร้างขึ้น วิธีการนี้ไม่มีการบันทึกข้อมูลไว้เนื่องจากมีเพียงเทมเพลตเท่านั้นที่ต้องใช้วิธีนี้ output
เป็นออบเจ็กต์ HtmlOutput
พิเศษที่มี 2 พร็อพเพอร์ตี้ที่มักไม่เกี่ยวข้อง ได้แก่ _
และ _$
ซึ่งเป็นคําย่อสําหรับการเรียก
append()
และ
appendUntrusted()
output
มีพร็อพเพอร์ตี้พิเศษอีก 1 รายการคือ $out
ซึ่งหมายถึงออบเจ็กต์ HtmlOutput
ปกติที่ไม่มีพร็อพเพอร์ตี้พิเศษเหล่านี้ เทมเพลตจะแสดงผลออบเจ็กต์ปกติเมื่อสิ้นสุดโค้ด
เมื่อเข้าใจไวยากรณ์นี้แล้ว โค้ดที่เหลือควรทําตามได้ง่าย เนื้อหา HTML นอกสคริปต์ (เช่น แท็ก b
) จะต่อท้ายโดยใช้ output._ =
(ไม่มีการใช้อักขระหลีกกับบริบท) และจะเพิ่มสคริปต์ต่อท้ายเป็น JavaScript (โดยมีหรือไม่มีการกําหนดเป็นบริบทก็ได้ ทั้งนี้ขึ้นอยู่กับประเภทของสคริปต์)
โปรดทราบว่าโค้ดที่ประเมินจะเก็บข้อมูลหมายเลขบรรทัดจากเทมเพลต หากคุณได้รับข้อผิดพลาดขณะเรียกใช้โค้ดที่ประเมิน บรรทัดจะสอดคล้องกับเนื้อหาที่เทียบเท่าในเทมเพลต
ลําดับชั้นของความคิดเห็น
เนื่องจากโค้ดที่ประเมินช่วยเก็บหมายเลขบรรทัด ความคิดเห็นภายใน สคริปต์จึงอาจแสดงความคิดเห็นในสคริปต์ย่อยอื่นๆ และแม้กระทั่งโค้ด 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. */ ?>