建立 mock 或 GAS 請求函式
修改檔案:script.js
完成後看見:頁面能取得固定欄位的回應
CHAPTER 21 · PRACTICE WORKSPACE
能用 mock 備援或教師 GAS URL 取得試算表資料
TASK STATUS
修改檔案:script.js
完成後看見:頁面能取得固定欄位的回應
修改檔案:script.js
完成後看見:空值與 Live 文字都以安全文字節點顯示
修改檔案:script.js
完成後看見:畫面區分 mock、空資料、合法 GAS /exec 與其他 JSON,live 失敗時可改用備援
WORKSPACE
已完成 TASK-01;先核對可見結果,再前往 TASK-02。
FOCUS TASK · TASK-02
比較:normalizeRows 處理欄位與空值,renderRows 只負責把已整理資料放到畫面。
現在做:在 Checkpoint 2 先只呼叫 normalizeRows([{ name: '', price: '' }]),記下 id、name、price 的結果;再把回傳值交給 renderRows(),比較兩個函式的輸入與輸出,不要把空值判斷塞進 createRowCard()。
預期:normalizeRows 先產出可預期的固定欄位,renderRows 只接收整理後的陣列並建立卡片;空名稱變成「未命名」、空價格變成 0。
證據:留下 Console 的正規化結果與畫面卡片,並用一句話分開說明「資料規則在 normalize,DOM 更新在 render」。
比較:Sheet 內容應當文字處理,不能因為方便就直接拼成可執行 HTML。
現在做:在 Checkpoint 2 將 name 暫時換成 <img id="unsafe-row" src=x onerror=alert(1)>,執行 renderRows(normalizeRows([row]));檢查 DOM 是否沒有 #unsafe-row,再用元素文字複製原始字串,最後保留 textContent 寫法。
預期:畫面看得到完整原始字串,但 DOM 沒有 img 元素、沒有事件執行;這個差異能證明外部 Sheet 文字不能用 innerHTML 直接插入。
證據:同時提供元素檢查結果「#unsafe-row 不存在」與卡片標題文字,並說明修復後仍可顯示原始內容。
完成條件:DONE-02:空值與 Live 文字都以安全文字節點顯示
MOCK 備援
尚未載入
CONTINUE
前往 Checkpoint 2,依要求完成「正規化並安全顯示 Sheet rows」。
CHAPTER HANDOFF
接收第 20 章:重用 loading、success、empty、error 四態;本章只新增 Sheet rows、資料正規化與 MOCK/LIVE/FALLBACK 的來源責任。
交給第 22 章:完成後帶著固定的 id、name、price rows、空資料提示與來源標示,下一章直接處理搜尋、篩選與分頁,不重做 GAS 或 normalize。