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