【手把手教學】打造即時更新的 Google 試算表連結系統(Apps Script + HTML 應用)
您是否厭倦了每次網站連結有變動,都必須手動修改網頁程式碼?本教學將教您如何利用 Google 試算表作為後端資料庫,結合 Google Apps Script 和前端 HTML/JavaScript 技術,打造一個無需修改程式碼,只需更新試算表內容,網頁連結清單即可即時更新的活動相簿或資源連結系統。
🎯 最終成果預覽
您將會得到一個獨立的 HTML 網頁(可儲存於本機或您的網站空間),它能:
自動讀取 Google 試算表中的「序號」、「相簿名稱」和「相簿網址」。
按照「序號」排序顯示連結清單。
支援左右翻頁,每頁顯示 10 個連結。
具備 RWD 響應式網頁設計,在電腦和手機上都能完美顯示(電腦為兩欄,手機為單欄)。
無需伺服器,完全免費!
呈現方式(鹿陽國小網站)
鹿陽活動相簿
🛠️ 準備工作
Google 帳號: 這是所有 Google 服務的基礎。
Google 試算表: 用來儲存連結資料。
Google Apps Script: 用來將試算表資料轉換成網頁可讀取的 JSON 格式。
步驟一:設定 Google 試算表資料庫
首先,我們需要一個結構化的資料來源。
建立試算表: 新建一個 Google 試算表,並將第一列設定為標題列。
設定欄位: 建立以下三個欄位:
A 欄:序號 (必須為數字):用於控制連結的顯示順序。
B 欄:相簿名稱:顯示在網頁上的連結文字。
C 欄:相簿網址:點擊後要前往的目標網址。
| 序號 | 相簿名稱 | 相簿網址 |
| 1 | 20250812_校園相片 | https://photos.app.goo.gl/... |
| 2 | 鹿陽校園 | https://photos.app.goo.gl/... |
| 11 | 20250917_班親會 | google.com (若無 https:// 會自動補上) |
| ... | ... | ... |
步驟二:部署 Apps Script 服務(JSON API)
Google Apps Script 是將試算表資料轉為網頁可讀格式(JSON)的關鍵。
開啟 Apps Script 編輯器: 在試算表上方菜單,點擊「擴充功能」→「Apps Script」。
貼上程式碼: 將以下 Apps Script 程式碼貼入
程式碼.gs檔案中,替換原有的內容。
程式碼.gs 內容 ()
function doGet() {
// 取得當前作用中試算表的第一個工作表
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
// 取得資料範圍:從第二列第一欄開始,讀取到最後一列,共讀取 3 欄 (序號、相簿名稱、相簿網址)
var data = sheet.getRange(2, 1, sheet.getLastRow() - 1, 3).getValues();
// 按序號排序(第一欄,索引為 0),確保連結列表是按照試算表中的序號排序顯示
data.sort(function(a, b) {
return a[0] - b[0];
});
// 將資料轉換為 JSON 字串並設定 MIME 類型
var jsonOutput = ContentService.createTextOutput(JSON.stringify(data));
jsonOutput.setMimeType(ContentService.MimeType.JSON);
return jsonOutput;
}
儲存專案: 點擊上方的儲存圖標。
部署成網路應用程式:
點擊右上角的「部署」→「新增部署作業」。
在「選取類型」中選擇「網路應用程式 (Web app)」。
執行身分:選擇「您自己」(這樣它就能讀取您的試算表)。
存取權:選擇「任何人」(這樣您的網頁才能讀取)。
點擊「部署」。
複製 URL: 部署成功後,會彈出一個視窗,請複製「網頁應用程式網址」(URL),這個網址就是我們的 JSON API 接口,請妥善保存。
步驟三:建立前端 HTML 頁面
接下來,我們將建立一個獨立的 photo.html 檔案,用於讀取 Apps Script 提供的 JSON 資料,並將其美化呈現。
建立
photo.html檔案: 在您的電腦上建立一個名為photo.html的純文字檔案。貼上程式碼: 將以下 HTML 程式碼貼入
photo.html檔案中。
photo.html 內容
請注意,您需要將程式碼中一個重要的常數替換成您在步驟二-5中複製的 Apps Script URL。
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>鹿陽活動相簿</title>
<style>
/* 樣式代碼,用於呈現圖片中的兩欄 RWD 佈局、顏色和動畫效果 */
body {
font-family: Arial, sans-serif;
margin: 0;
background-color: #f4f4f9;
color: #333;
}
.container {
max-width: 900px;
margin: 50px auto;
padding: 20px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
position: relative;
}
/* 標題區塊 */
.header {
border-bottom: 2px solid #e1b452;
padding-bottom: 10px;
margin-bottom: 20px;
display: flex;
justify-content: space-between;
align-items: flex-end;
}
h1 {
color: #5a5a5a;
font-size: 1.8em;
margin: 0;
}
/* 模擬圖片中的建築裝飾 */
.decoration {
width: 100px;
height: 30px;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 30"><path fill="%23e1b452" d="M 0 30 L 0 10 Q 5 0, 10 10 T 20 10 T 30 10 T 40 10 T 50 10 T 60 10 T 70 10 T 80 10 T 90 10 L 100 0 L 100 30 Z"/></svg>');
background-size: contain;
background-repeat: no-repeat;
}
/* 連結容器 - 桌面模式 (5行 x 2欄) */
#link-list {
position: relative;
overflow: hidden;
height: 380px;
}
.page-container {
width: 100%;
display: flex;
transition: transform 0.5s ease-in-out;
}
.link-page {
min-width: 100%;
box-sizing: border-box;
padding: 0 10px;
}
/* 網格佈局:兩欄,每欄五個 */
.link-grid {
list-style-type: none;
padding: 0;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px 30px;
}
li {
padding: 15px 12px;
background-color: #fff8e8;
display: flex;
align-items: center;
border-bottom: 1px solid #fff8e8;
}
li:hover {
background-color: #ffe6b0;
transition: background-color 0.3s;
}
.link-icon {
margin-right: 15px;
color: #e1b452;
font-size: 1.2em;
}
a {
text-decoration: none;
color: #333;
font-size: 1em;
flex-grow: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
a:hover {
text-decoration: none;
color: #007bff;
}
a:visited {
color: #333;
}
#loading {
font-size: 1.2em;
color: #888;
text-align: center;
padding: 50px;
}
/* 翻頁控制項 */
.pagination-controls {
position: absolute;
top: 50%;
width: 100%;
display: flex;
justify-content: space-between;
pointer-events: none;
transform: translateY(-50%);
}
.arrow {
font-size: 2.5em;
color: #e1b452;
cursor: pointer;
padding: 0 5px;
pointer-events: auto;
user-select: none;
opacity: 0.7;
transition: opacity 0.3s;
}
.arrow:hover:not(.disabled) {
opacity: 1;
}
.arrow.disabled {
color: #ccc;
cursor: default;
opacity: 0.3;
}
/* 頁碼點點 */
.page-dots {
text-align: center;
margin-top: 15px;
}
.dot {
height: 10px;
width: 10px;
margin: 0 4px;
background-color: #ddd;
border-radius: 50%;
display: inline-block;
transition: background-color 0.3s;
}
.dot.active {
background-color: #e1b452;
}
/* RWD Media Query: 響應式網頁設計 - 寬度不足時切換為單欄 */
@media (max-width: 600px) {
.container {
max-width: 100%;
margin: 20px 10px;
padding: 15px;
}
.header h1 {
font-size: 1.5em;
}
.decoration {
display: none;
}
/* 連結容器改為單欄 (10個項目垂直堆疊) */
.link-grid {
grid-template-columns: 1fr;
gap: 0;
}
/* 調整列表高度以容納 10 個項目堆疊 */
#link-list {
height: 550px;
}
li {
padding: 12px 10px;
background-color: #fff8e8;
border-bottom: 1px solid #e9e9e9;
}
li:last-child {
border-bottom: none;
}
/* 翻頁箭頭調整 */
.arrow {
font-size: 2em;
padding: 0 10px;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>鹿陽活動相簿</h1>
<div class="decoration"></div>
</div>
<div id="loading">讀取中...</div>
<div id="link-list">
<div class="page-container" id="page-container">
</div>
<div class="pagination-controls">
<span id="prev-btn" class="arrow disabled" onclick="manualChangePage(-1)" role="button" aria-controls="link-list" aria-label="上一頁"><</span>
<span id="next-btn" class="arrow" onclick="manualChangePage(1)" role="button" aria-controls="link-list" aria-label="下一頁">></span>
</div>
</div>
<div class="page-dots" id="page-dots" role="tablist">
</div>
</div>
<script>
// **重要:將此 URL 替換為您部署 Apps Script 網頁應用程式後的 URL**
// 請將此行替換成您在步驟二-5中複製的實際網址
const APPS_SCRIPT_URL = 'https://script.google.com/macros/s/AKfycbxj8-L4N7lhnYcqbgLiEdWBbg7s_Saoxe-fZaQXpTB7_YYq3qKl_zCuFz-Lk4aBMdBvkQ/exec';
const pageContainer = document.getElementById('page-container');
const loadingMessage = document.getElementById('loading');
const prevBtn = document.getElementById('prev-btn');
const nextBtn = document.getElementById('next-btn');
const pageDots = document.getElementById('page-dots');
const LINKS_PER_PAGE = 10;
const AUTO_SLIDE_INTERVAL = 5000;
let allData = [];
let currentPage = 0;
let totalPages = 0;
let autoSlideTimer;
/**
* 繪製單一頁面的連結
*/
function renderPage(pageIndex) {
const start = pageIndex * LINKS_PER_PAGE;
const end = start + LINKS_PER_PAGE;
const pageData = allData.slice(start, end);
const pageDiv = document.createElement('div');
pageDiv.classList.add('link-page');
const linkGrid = document.createElement('ul');
linkGrid.classList.add('link-grid');
pageData.forEach(row => {
const index = row[0];
const name = row[1];
let url = row[2];
if (name && url) {
// 如果網址不是以 https:// 或 http:// 開頭,則自動加上 https://
if (typeof url === 'string' && !url.match(/^https?:\/\//)) {
url = 'https://' + url;
}
const listItem = document.createElement('li');
// 使用三角形圖標代替序號,符合無障礙網站要求,使用 target="_blank" 和 title 說明會另開新視窗
listItem.innerHTML = `<span class="link-icon" aria-hidden="true">▶</span> <a href="${url}" target="_blank" title="${name}(另開新視窗)" rel="noopener noreferrer">${name}</a>`;
linkGrid.appendChild(listItem);
}
});
pageDiv.appendChild(linkGrid);
pageContainer.appendChild(pageDiv);
}
/**
* 更新翻頁按鈕和頁碼點點的狀態
*/
function updateControls() {
prevBtn.classList.toggle('disabled', currentPage === 0);
nextBtn.classList.toggle('disabled', currentPage === totalPages - 1 || totalPages === 0);
// 更新頁碼點點
pageDots.innerHTML = '';
for (let i = 0; i < totalPages; i++) {
const dot = document.createElement('span');
dot.classList.add('dot');
// 為點點新增無障礙屬性
dot.setAttribute('role', 'tab');
dot.setAttribute('aria-label', `前往第 ${i + 1} 頁`);
dot.setAttribute('tabindex', '0'); // 使其可被鍵盤選中
if (i === currentPage) {
dot.classList.add('active');
dot.setAttribute('aria-selected', 'true');
} else {
dot.setAttribute('aria-selected', 'false');
}
// 點擊點點時暫停自動播放
dot.onclick = () => {
stopAutoSlide();
goToPage(i);
};
// 支援鍵盤 Enter 鍵切換
dot.onkeypress = (e) => {
if (e.key === 'Enter') {
stopAutoSlide();
goToPage(i);
}
};
pageDots.appendChild(dot);
}
}
/**
* 切換頁面 (核心邏輯)
*/
function goToPage(pageIndex) {
if (pageIndex < 0 || pageIndex >= totalPages) return;
currentPage = pageIndex;
const offset = -currentPage * 100;
pageContainer.style.transform = `translateX(${offset}%)`;
updateControls();
}
/**
* 自動翻頁邏輯:循環到下一頁
*/
function nextSlide() {
const nextIndex = (currentPage + 1) % totalPages;
goToPage(nextIndex);
}
/**
* 啟動自動翻頁
*/
function startAutoSlide() {
if (totalPages > 1) {
if (autoSlideTimer) {
clearInterval(autoSlideTimer);
}
// 設定新的計時器
autoSlideTimer = setInterval(nextSlide, AUTO_SLIDE_INTERVAL);
}
}
/**
* 停止自動翻頁
*/
function stopAutoSlide() {
if (autoSlideTimer) {
clearInterval(autoSlideTimer);
autoSlideTimer = null;
}
}
/**
* 手動翻頁 (左右箭頭)
*/
function manualChangePage(delta) {
stopAutoSlide();
goToPage(currentPage + delta);
}
// 將手動翻頁函數暴露給 HTML 元素的 onclick 屬性
window.manualChangePage = manualChangePage;
/**
* 主要資料讀取函數
*/
function fetchAndRenderLinks() {
if (APPS_SCRIPT_URL.includes('AKfycbxj8-L4N7lhnYcqbgLiEdWBbg7s_Saoxe-fZaQXpTB7_YYq3qKl_zCuFz-Lk4aBMdBvkQ/exec')) {
// 這裡檢查是否為預設的 URL,提醒用戶替換
loadingMessage.textContent = '請在程式碼中替換 Apps Script 的 URL。';
return;
}
fetch(APPS_SCRIPT_URL)
.then(response => {
if (!response.ok) {
throw new Error('網路回應有問題');
}
return response.json();
})
.then(data => {
loadingMessage.style.display = 'none';
// 過濾掉無效資料,只保留有相簿名稱和網址的項目
allData = data.filter(row => row[1] && row[2]);
if (allData.length === 0) {
loadingMessage.style.display = 'block';
loadingMessage.textContent = '試算表中沒有資料。';
return;
}
// 計算總頁數
totalPages = Math.ceil(allData.length / LINKS_PER_PAGE);
// 循環資料並生成所有頁面
for (let i = 0; i < totalPages; i++) {
renderPage(i);
}
// 顯示第一頁並更新控制項
goToPage(0);
// 開始自動翻頁
startAutoSlide();
})
.catch(error => {
loadingMessage.style.display = 'block';
loadingMessage.textContent = '讀取資料時發生錯誤:' + error.message;
console.error('Fetch Error:', error);
});
}
fetchAndRenderLinks();
</script>
<a href="https://docs.google.com/spreadsheets/d/15zqf581Gj_hEy9Kr3Tlgcsw-_C8jIBnaOf2OSBJzD2s/edit?usp=sharing" target="_blank" style="display:block; text-align:center; margin-top: 20px; font-size: 1.1em; color: #5a5a5a; text-decoration: none;">編輯活動相簿資料</a>
</body>
</html>
步驟四:運行與測試
開啟網頁: 雙擊您電腦上的
photo.html檔案。它會使用您的預設瀏覽器開啟。確認資料: 網頁應會顯示「讀取中...」後,載入您試算表中的前 10 個連結,並以您提供的圖片佈局呈現。
測試即時性:
開啟您的 Google 試算表。
新增一筆資料或修改現有連結的「相簿名稱」或「相簿網址」。
回到
photo.html頁面,重新整理瀏覽器。您會發現網頁上的連結已經同步更新!
恭喜您!您已成功建立一個由 Google 試算表驅動,具備 RWD 和自動播放功能的連結清單系統。這套系統大大降低了日常維護的複雜度,讓您專注於內容管理。
沒有留言:
張貼留言