雖然還是在用Spreadsheet,這篇文章實際重點是在…Google App Script也就是Google指令碼的使用,會用到其中的HtmlService(製作模板)、Spreadsheet(取得資料),用這種方式來製作專題的html!
現代架站多是使用像是wordpress、joomla之類的架站工具,有現成的cms讓使用者把內容寫進資料庫,內容呈現在固定的網頁版型中。有些比較臨時性的內容(如活動、專題)因為特別的規格與設計需求,則需由網頁設計師、前端工程師製作。一次性使用,沒後台也沒問題。但!如果往後還想再用同樣的版型,卻不想佔據設計師、工程師大大寶貴時間在複製貼上,又不確定開發後台是否符合成本(開了後台用10次?合嗎?)我來玩玩用spreadsheet填資料、產html的方法!
概念很簡單,就是把要更換的內容寫在spreadsheet,把這些內容置換進html裡就是了。(跟用後台是一樣,後台文章編輯介面就是一個form,編輯存進資料庫以後,當有人點開該連結,程式就會把資料置換進html模板)
這次的成品在此:http://www.cna.com.tw/project/cards/20171002-catalonia/
準備:
- 一張試算表
- 專題html作為模板
- 資料夾(存好css、js、img)
讓編輯填格子不會太難(而且可以讓他們用Spreadsheet的功能選定標題顏色、header背景色喔❤️)…但是要怎麼把這些內容換進html呢?接下來要使用Google app script囉!
- Spreadsheet指令列> 工具> 指令碼編輯器>
- 檔案> 新增> 指令碼檔案
- 檔案> 新增> HTML檔案,命名為index.html
Google App Script指令碼檔案,主要是處理1. 開模板 2. 取得資料 3. 套用資料
function doGet() {
// 使用htmlservice的從檔案製作模板,把模板叫做t
var t = HtmlService.createTemplateFromFile('index.html'); // 取得編輯填寫內容的Spreadsheet位置
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("卡片式特企模板"); // head顏色處理
var headerbg = sheet.getRange("B3").getBackground();
var titlecolor = sheet.getRange("B3").getFontColor();
var descolor = sheet.getRange("B4").getFontColor();
var color = [headerbg,titlecolor,descolor]; // 模板t的色彩資料叫datac,內容是color這個陣列
t.datac = color; // meta處理,meta資料叫datam,取得B2:B9的資料 (開始列號、開始欄號、移動列數、移動欄數)
t.datam = sheet.getRange(2,2,9,1).getValues(); // 內文處理,先確認有幾組內容(一方面用在模板裡決定迴圈次數,一方面計算出資料要抓到哪裡)
var pair = sheet.getRange("B9").getValue();
var cont = sheet.getRange(10,2,pair*6,1).getValues();
t.datap = pair; t.data = cont; // 模板套用資料,並且取得模板html內容,取名為final
var final = t.evaluate().getContent(); // 把final吐到儲存格
var output = sheet.getRange("D2");
output.clearContent(); output.setValue(final);}
模板html,把要填入資料的地方以 <?= ?> 挖出來,例如說:
<title> <?= datam[1] ?> | 中央社 CNA NEWS</title>
在模板運作後,在html裡就會是:
<title>加泰隆尼亞鐵了心脫離西班牙 獨立公投一面倒 | 中央社 CNA NEWS</title>
- datam[0]是網址:20171002-catalonia;
- datam[1]就是下一格:加泰隆尼亞鐵了心脫離西班牙 獨立公投一面倒。其他地方依此類推囉。
要寫程式語法的時候則是 <? ?>,例如說:
//判斷有沒有延伸閱讀連結:<? if (data[6*i+5]!=""){ ?>
<a class="more" href="<?=data[6*i+5]?>" target="_blank">延伸閱讀<i class="mdi mdi-open-in-new"></i></a>
<? } else { ?>
<? } ?>>
實際樣子:
<title><?=datam[1]?> | 中央社 CNA NEWS</title>...<meta property="og:image" content="http://www.cna.com.tw/project/cards/<?=datam[0]?><?=datam[3]?>" /><meta property="og:title" content="<?=datam[1]?> | 中央社" /><meta property="og:url" content="http://www.cna.com.tw/project/cards/<?=datam[0]?>/index.html"/>...<div class="row headerRow" style="background-color:<?=datac[0]?>; color:<?=datac[2]?>;">...<h1 style="color:<?=datac[1]?>"><?=datam[1]?></h1><p><?datam[2]?></p>... //因為卡片區塊都是一樣的,所以開始依數量跑迴圈<? for (var i = 0; i < datap; i++) { ?>
<div class="itembox">
<div class="mediaWrap"> //雖然卡片區格式一樣,但是左欄因為放影片、內嵌fb、一般照片,需要讀入不同的html,所以寫判斷:
<? if (data[6*i+1]!=""){ ?> //如果一組內容的第二格不是空白的話,代表有影片,要出video tag <video class="video-js vjs-default-skin" controls="" preload="none" poster="<?=data[6*i]?>">
<source src="<?=data[6*i+1]?>" type="video/mp4" />
<source src="<?=data[6*i+2]?>" type="video/ogg" />
<p>您的瀏覽器不支援播放此影片,請試試影片下載<a href="<?=data[6*i+1]?>">下載點</a></p>
</video>
</div> <? } else if (data[6*i].indexOf("iframe") < 0){ ?> //如果一組內容的第一格中沒有iframe的話,要出img tag <div><img src="<?=data[6*i]?>"></div>
</div> <? } else {?> <div><?=data[6*i]?></div> <? } ?> //右欄文字說明 <div class="textWrap">
<h2 class="clamp-Title"><?=data[6*i+3]?></h2>
<p class="clamp-Txt"><?=data[6*i+4]?></p>
</div> //判斷有沒有延伸閱讀連結: <? if (data[6*i+5]!=""){ ?>
<a class="more" href="<?=data[6*i+5]?>" target="_blank">延伸閱讀<i class="mdi mdi-open-in-new"></i></a>
<? } else { ?>
<? } ?> </div>
<? } ?>
要注意的點是,在html模板裡面挖洞的時候要小心 <?= ?> <? ?>的完整性,因為夾雜在html code中,一個小地方錯,跑程式就會出錯,html在Google指令碼編輯器中沒有偵錯功能,要找缺漏的地方,會花很久時間 orz…
- 既然都可以用Spreadsheet當後台了,那什麼不乾脆開一個資料庫做成動態網頁?!因為…小弟只是個PM,不是攻城師大大啊 orz
【2019.8更新】️⬆⬆⬆真的做出來了:
- 進html一個一個填入資料有什麼難?但我自己實際運作真的很瑣碎,像光是「網址」要置換的地方可多的!og:image、og:url、分享的網址,以變數套用還是比較方便、避免錯誤。套句這網誌成立的名言:一個小編一天省10分鐘,10個小編一週可以省500分鐘,一個月可以省183小時(也就是一個月省一個人力的意思)。
參考資料:
Originally published at 35.229.214.198 on October 14, 2017.