<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="pretty-atom-feed.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hant">
  <title>光輝咖碼</title>
  <subtitle>沒有一杯咖啡解決不了的問題；如果有，就交給 AI 吧。這裡分享網站架設、前端開發與各種技術筆記，然後再來一杯。</subtitle>
  <link href="https://kamadiam.com/feed/feed.xml" rel="self" />
  <link href="https://kamadiam.com/" />
  <updated>2026-09-01T02:00:00Z</updated>
  <id>https://kamadiam.com/</id>
  <author>
    <name>huihere</name>
  </author>
  <entry>
    <title>PageSpeed Insights 怎麼改善？實戰教學（LCP／INP／CLS 對照表）</title>
    <link href="https://kamadiam.com/pagespeed-insights-tutorial/" />
    <updated>2026-09-01T02:00:00Z</updated>
    <id>https://kamadiam.com/pagespeed-insights-tutorial/</id>
    <content type="html">&lt;p&gt;打開 &lt;a href=&quot;https://pagespeed.web.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PageSpeed Insights&lt;/a&gt;（PSI）輸入網址，分數不理想時，下一步通常不是「再測一次祈禱變綠」，而是&lt;strong&gt;對照診斷項目逐項修&lt;/strong&gt;。這篇專注在「怎麼改善」：怎麼讀 PSI 報告、三項 Core Web Vitals 該修哪裡、以及 WordPress 與靜態站都能套用的實戰 Checklist。&lt;/p&gt;&lt;p&gt;指標定義與實地／實驗室資料差異，可搭配閱讀 &lt;a href=&quot;https://kamadiam.com/pagespeed-core-web-vitals/&quot;&gt;PageSpeed Insights 與 Core Web Vitals 完全指南&lt;/a&gt;。若你維護的是 11ty 靜態站，另可參考 &lt;a href=&quot;https://kamadiam.com/11ty-pagespeed-insights-optimization-workflow/&quot;&gt;11ty 網站 PSI 優化工作流&lt;/a&gt;。&lt;/p&gt;&lt;h2 id=&quot;快速參考&quot;&gt;快速參考&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;項目&lt;/th&gt;&lt;th&gt;說明&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;工具&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://pagespeed.web.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;pagespeed.web.dev&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;三項核心指標&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;LCP（載入）、INP（互動）、CLS（穩定）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;良好門檻（p75）&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;LCP ≤ 2.5s、INP ≤ 200ms、CLS ≤ 0.1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;先看哪個&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;有 CrUX 實地資料 → 以實地為準；沒有 → 用 Lighthouse 診斷找問題&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;常見第一刀&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;壓縮 LCP 圖片、補 width/height、延後第三方腳本&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagespeed-insights-tutorial/#%E5%BF%AB%E9%80%9F%E5%8F%83%E8%80%83&quot;&gt;快速參考&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagespeed-insights-tutorial/#%E7%AC%AC%E4%B8%80%E6%AD%A5%E6%80%8E%E9%BA%BC%E7%94%A8-PageSpeed-Insights-%E6%B8%AC%E8%A9%A6&quot;&gt;第一步：怎麼用 PageSpeed Insights 測試&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagespeed-insights-tutorial/#Core-Web-Vitals-%E9%96%80%E6%AA%BB%E9%80%9F%E6%9F%A5&quot;&gt;Core Web Vitals 門檻速查&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagespeed-insights-tutorial/#LCP-%E6%80%8E%E9%BA%BC%E6%94%B9%E5%96%84&quot;&gt;LCP 怎麼改善&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagespeed-insights-tutorial/#INP-%E6%80%8E%E9%BA%BC%E6%94%B9%E5%96%84&quot;&gt;INP 怎麼改善&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagespeed-insights-tutorial/#CLS-%E6%80%8E%E9%BA%BC%E6%94%B9%E5%96%84&quot;&gt;CLS 怎麼改善&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagespeed-insights-tutorial/#30-%E5%88%86%E9%90%98%E6%94%B9%E5%96%84-Checklist&quot;&gt;30 分鐘改善 Checklist&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagespeed-insights-tutorial/#3-%E5%80%8B%E6%94%B9%E5%96%84%E6%A1%88%E4%BE%8B%E6%96%B9%E5%90%91%E5%8F%83%E8%80%83&quot;&gt;3 個改善案例（方向參考）&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagespeed-insights-tutorial/#%E5%B8%B8%E8%A6%8B%E8%AA%A4%E5%8D%80&quot;&gt;常見誤區&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagespeed-insights-tutorial/#%E5%85%B6%E4%BB%96%E5%AF%A6%E7%94%A8%E5%B7%A5%E5%85%B7&quot;&gt;其他實用工具&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagespeed-insights-tutorial/#%E5%B8%B8%E8%A6%8B%E5%95%8F%E9%A1%8C&quot;&gt;常見問題&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagespeed-insights-tutorial/#%E7%B5%90%E8%AA%9E&quot;&gt;結語&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/pagespeed-insights-tutorial/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;第一步怎麼用-PageSpeed-Insights-測試&quot;&gt;第一步：怎麼用 PageSpeed Insights 測試&lt;/h2&gt;&lt;ol&gt;&lt;li&gt;開啟 &lt;a href=&quot;https://pagespeed.web.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PageSpeed Insights&lt;/a&gt;&lt;/li&gt;&lt;li&gt;輸入完整網址（建議先測首頁與流量最高的文章各一頁）&lt;/li&gt;&lt;li&gt;分別查看&lt;strong&gt;手機&lt;/strong&gt;與&lt;strong&gt;電腦&lt;/strong&gt;結果&lt;/li&gt;&lt;li&gt;記下三項 Core Web Vitals 的顏色（綠／橘／紅）與 Lighthouse 診斷清單&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;PSI 通常提供兩種資料：&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;類型&lt;/th&gt;&lt;th&gt;來源&lt;/th&gt;&lt;th&gt;用途&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;實地資料（Field Data）&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Chrome 使用者體驗報告（CrUX）&lt;/td&gt;&lt;td&gt;反映真實使用者最近 28 天的體驗&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;實驗室資料（Lab Data）&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Lighthouse 模擬載入&lt;/td&gt;&lt;td&gt;找出可能拖慢的原因與改善建議&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;新站或流量不足的網址可能沒有網址層級的 CrUX 資料，這時以 Lighthouse 診斷為主，並在 Search Console 觀察累積後的趨勢。一次測試的分數會波動，不要只因為某天掉到 70 分就 panic；重點是&lt;strong&gt;同一 URL、同一裝置類型&lt;/strong&gt;下，改動前後的對比。&lt;/p&gt;&lt;h2 id=&quot;Core-Web-Vitals-門檻速查&quot;&gt;Core Web Vitals 門檻速查&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;指標&lt;/th&gt;&lt;th&gt;看什麼&lt;/th&gt;&lt;th&gt;良好&lt;/th&gt;&lt;th&gt;需要改善&lt;/th&gt;&lt;th&gt;不佳&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;LCP&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;主要內容多久出現&lt;/td&gt;&lt;td&gt;≤ 2.5 秒&lt;/td&gt;&lt;td&gt;&amp;gt; 2.5–4 秒&lt;/td&gt;&lt;td&gt;&amp;gt; 4 秒&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;INP&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;點擊後多久有回應&lt;/td&gt;&lt;td&gt;≤ 200 毫秒&lt;/td&gt;&lt;td&gt;&amp;gt; 200–500 毫秒&lt;/td&gt;&lt;td&gt;&amp;gt; 500 毫秒&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;CLS&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;版面是否跳動&lt;/td&gt;&lt;td&gt;≤ 0.1&lt;/td&gt;&lt;td&gt;&amp;gt; 0.1–0.25&lt;/td&gt;&lt;td&gt;&amp;gt; 0.25&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：FID 已被 INP 取代。若你看到舊文還在講 FID，請以 INP 為準。&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;三項都達到 Good（看實地資料的第 75 百分位）才算通過 Core Web Vitals 評估。Lighthouse 變綠有助除錯，但不等於搜尋排名會立刻起飛——內容相關性與整體體驗同樣重要。&lt;/p&gt;&lt;h2 id=&quot;LCP-怎麼改善&quot;&gt;LCP 怎麼改善&lt;/h2&gt;&lt;p&gt;LCP（Largest Contentful Paint）衡量首屏最大內容元素完成繪製的時間，常見是 hero 圖、大標題或主要文字區塊。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;先在 PSI 確認 LCP 元素是哪一個&lt;/strong&gt;，再對症下藥：&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;問題方向&lt;/th&gt;&lt;th&gt;常見原因&lt;/th&gt;&lt;th&gt;改善做法&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;伺服器慢&lt;/td&gt;&lt;td&gt;TTFB 過高&lt;/td&gt;&lt;td&gt;換主機／CDN、啟用快取、靜態化&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;圖片太大&lt;/td&gt;&lt;td&gt;LCP 是未壓縮的大圖&lt;/td&gt;&lt;td&gt;WebP／AVIF、responsive &lt;code&gt;srcset&lt;/code&gt;、適當尺寸&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;發現太晚&lt;/td&gt;&lt;td&gt;關鍵圖被 lazy-load&lt;/td&gt;&lt;td&gt;&lt;strong&gt;首屏 LCP 圖不要 lazy&lt;/strong&gt;；必要時 &lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;渲染阻塞&lt;/td&gt;&lt;td&gt;CSS／同步 JS 擋住繪製&lt;/td&gt;&lt;td&gt;精簡關鍵 CSS、延後非關鍵腳本&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;靜態站可參考 &lt;a href=&quot;https://kamadiam.com/lcp-optimization-no-lazy-fetchpriority/&quot;&gt;LCP 優化：首屏別 lazy-load&lt;/a&gt;；WordPress 可搭配圖片外掛與快取外掛，但記得&lt;strong&gt;先確認 LCP 元素&lt;/strong&gt;，不要對所有圖片盲目 preload。&lt;/p&gt;&lt;h2 id=&quot;INP-怎麼改善&quot;&gt;INP 怎麼改善&lt;/h2&gt;&lt;p&gt;INP（Interaction to Next Paint）觀察頁面生命週期中的點擊、點按與鍵盤互動，評估從互動到下一幀繪製的延遲。&lt;/p&gt;&lt;p&gt;常見拖慢原因：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;第三方分析、廣告、聊天 widget 佔滿主執行緒&lt;/li&gt;&lt;li&gt;過大的 JavaScript bundle 或長任務（&amp;gt; 50ms）&lt;/li&gt;&lt;li&gt;載入期間就綁了大量事件處理&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;改善方向：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;延後非必要腳本&lt;/strong&gt;（GTM、社群分享、留言系統）到 &lt;code&gt;requestIdleCallback&lt;/code&gt; 或使用者互動後&lt;/li&gt;&lt;li&gt;&lt;strong&gt;切割長任務&lt;/strong&gt;，避免在 click handler 裡做大量同步運算&lt;/li&gt;&lt;li&gt;&lt;strong&gt;減少第三方數量&lt;/strong&gt;，定期審計真的還需要的 widget&lt;/li&gt;&lt;li&gt;用 Chrome DevTools Performance 錄製「載入中點選單」等真實流程&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;可參考 &lt;a href=&quot;https://kamadiam.com/gtm-defer-requestidlecallback-psi-optimization/&quot;&gt;GTM 延遲載入&lt;/a&gt; 降低 TBT／INP 壓力。&lt;/p&gt;&lt;h2 id=&quot;CLS-怎麼改善&quot;&gt;CLS 怎麼改善&lt;/h2&gt;&lt;p&gt;CLS（Cumulative Layout Shift）衡量版面在載入過程中意外位移的程度。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;常見原因&lt;/th&gt;&lt;th&gt;解法&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;圖片沒預留空間&lt;/td&gt;&lt;td&gt;為 &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; 設定 &lt;code&gt;width&lt;/code&gt;／&lt;code&gt;height&lt;/code&gt; 或 &lt;code&gt;aspect-ratio&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;廣告／嵌入突然插入&lt;/td&gt;&lt;td&gt;預留固定高度容器&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;網頁字型造成跳動&lt;/td&gt;&lt;td&gt;&lt;code&gt;font-display: swap&lt;/code&gt; 或子集化；參考 &lt;a href=&quot;https://kamadiam.com/font-subsetting-reduce-font-loading/&quot;&gt;字型子集化&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;動態插入內容&lt;/td&gt;&lt;td&gt;先佔位再載入，或固定容器高度&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;詳解可見 &lt;a href=&quot;https://kamadiam.com/image-size-cls-preallocation/&quot;&gt;圖片尺寸與 CLS 預防&lt;/a&gt;。&lt;/p&gt;&lt;h2 id=&quot;30-分鐘改善-Checklist&quot;&gt;30 分鐘改善 Checklist&lt;/h2&gt;&lt;p&gt;以下流程假設你有一個 WordPress 或類似 CMS 的網站；靜態站把「快取外掛」換成 build 時的圖片與資產優化即可。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;時間&lt;/th&gt;&lt;th&gt;任務&lt;/th&gt;&lt;th&gt;預期效果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;0–5 分&lt;/td&gt;&lt;td&gt;跑 PSI，記錄 LCP／INP／CLS 基線與 LCP 元素&lt;/td&gt;&lt;td&gt;建立對照基準&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5–10 分&lt;/td&gt;&lt;td&gt;啟用伺服器／頁面快取&lt;/td&gt;&lt;td&gt;改善 TTFB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;10–15 分&lt;/td&gt;&lt;td&gt;壓縮 LCP 圖片為 WebP；首屏圖取消 lazy&lt;/td&gt;&lt;td&gt;LCP 通常最明顯&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;15–20 分&lt;/td&gt;&lt;td&gt;為所有內容圖補 width/height&lt;/td&gt;&lt;td&gt;CLS 下降&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;20–25 分&lt;/td&gt;&lt;td&gt;延後 GTM／第三方腳本；移除未使用外掛&lt;/td&gt;&lt;td&gt;INP／TBT 改善&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;25–30 分&lt;/td&gt;&lt;td&gt;再跑 PSI，對比診斷變化&lt;/td&gt;&lt;td&gt;驗證有效改動&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;strong&gt;不要一次開滿所有「極速」選項&lt;/strong&gt;（例如 JS/CSS 全部合併＋延遲到離譜）。分數可能變 100，但版面爆炸或追蹤失效，使用者體驗反而更差。&lt;/p&gt;&lt;h2 id=&quot;3-個改善案例方向參考&quot;&gt;3 個改善案例（方向參考）&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;案例 1：WordPress 部落格（LCP 4.2s → 1.8s）&lt;/strong&gt;&lt;br&gt;啟用快取 + WebP 圖片 + 移除 3 個未使用外掛，並取消 hero 圖 lazy-load。PSI 行動分數從 40 多提升到 70 多。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;案例 2：電商網站（CLS 0.25 → 0.05）&lt;/strong&gt;&lt;br&gt;為商品圖補 &lt;code&gt;width&lt;/code&gt;/&lt;code&gt;height&lt;/code&gt;，廣告區塊預留空間，CLS 進入綠色區間。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;案例 3：11ty 靜態站（TTFB 改善 + LCP 綠燈）&lt;/strong&gt;&lt;br&gt;CDN 部署 + 響應式圖片管道 + 關鍵字體子集化。詳細流程見 &lt;a href=&quot;https://kamadiam.com/11ty-pagespeed-insights-optimization-workflow/&quot;&gt;11ty PSI 優化工作流&lt;/a&gt;。&lt;/p&gt;&lt;h2 id=&quot;常見誤區&quot;&gt;常見誤區&lt;/h2&gt;&lt;h3 id=&quot;分數高就代表-SEO-一定好?&quot;&gt;分數高就代表 SEO 一定好？&lt;/h3&gt;&lt;p&gt;Core Web Vitals 是排名訊號之一，不是唯一因素。Brian Dean 等實驗也顯示「速度」與排名相關，但不是線性對應。優化速度是為了&lt;strong&gt;使用者體驗&lt;/strong&gt;，順便滿足 Google 的體驗訊號。&lt;/p&gt;&lt;h3 id=&quot;自己開很快,訪客就一定快?&quot;&gt;自己開很快，訪客就一定快？&lt;/h3&gt;&lt;p&gt;開發者通常有更好的網路與裝置。要以 CrUX 實地資料或 Search Console 的體驗報告為準，不要只憑本機 Lighthouse 自我安慰。&lt;/p&gt;&lt;h3 id=&quot;實驗室滿分-=-實地資料也會綠?&quot;&gt;實驗室滿分 = 實地資料也會綠？&lt;/h3&gt;&lt;p&gt;不一定。實地資料受使用者裝置、地區、網路影響。實驗室幫你找問題，實地資料才反映真實世界。&lt;/p&gt;&lt;h3 id=&quot;只優化首頁夠嗎?&quot;&gt;只優化首頁夠嗎？&lt;/h3&gt;&lt;p&gt;不夠。文章頁、分類頁若 LCP 是大型內文圖，也要逐頁檢查。Search Console 的「核心網頁指標」報告會列出需要改善的 URL 群組。&lt;/p&gt;&lt;h2 id=&quot;其他實用工具&quot;&gt;其他實用工具&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;工具&lt;/th&gt;&lt;th&gt;用途&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Chrome DevTools Lighthouse&lt;/a&gt;&lt;/td&gt;&lt;td&gt;本機重現問題&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://chromewebstore.google.com/detail/web-vitals/ahfhijdlegdabablpippeagghigmibma&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Web Vitals 擴充功能&lt;/a&gt;&lt;/td&gt;&lt;td&gt;即時看 LCP／INP／CLS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://www.webpagetest.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;WebPageTest&lt;/a&gt;&lt;/td&gt;&lt;td&gt;多地點、多瀏覽器測試&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Google Search Console&lt;/td&gt;&lt;td&gt;全站 CrUX 趨勢與問題 URL&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h2 id=&quot;常見問題&quot;&gt;常見問題&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;PageSpeed Insights 適用行動裝置嗎？&lt;/strong&gt;&lt;br&gt;是的，PSI 分別提供手機與電腦報告，兩者都要看。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;一定要懂程式才能改善嗎？&lt;/strong&gt;&lt;br&gt;基礎項目（快取、圖片壓縮、移除外掛）不一定需要寫 code；模板層級的 LCP／CLS 修正則可能需要開發者協助。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;第三方廣告會影響分數嗎？&lt;/strong&gt;&lt;br&gt;會。廣告腳本常拖慢 INP 並造成 CLS，需預留空間並評估是否值得保留。&lt;/p&gt;&lt;h2 id=&quot;結語&quot;&gt;結語&lt;/h2&gt;&lt;p&gt;PageSpeed Insights 改善的本質是：&lt;strong&gt;先量測 → 找到 LCP 元素與最長任務 → 一次改一類問題 → 再驗證&lt;/strong&gt;。不要追逐單次滿分，而要讓真實使用者在載入、互動與閱讀時都更順。&lt;/p&gt;&lt;p&gt;下一步建議：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;今天先測首頁 + 一篇熱門文章，記錄基線&lt;/li&gt;&lt;li&gt;優先處理 LCP 圖片與 CLS 的 width/height&lt;/li&gt;&lt;li&gt;需要完整指標解讀時，閱讀 &lt;a href=&quot;https://kamadiam.com/pagespeed-core-web-vitals/&quot;&gt;Core Web Vitals 完全指南&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://pagespeed.web.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PageSpeed Insights&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/vitals&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;web.dev：Core Web Vitals&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/optimize-lcp&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;web.dev：Optimize LCP&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/optimize-inp&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;web.dev：Optimize INP&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/optimize-cls&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;web.dev：Optimize CLS&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>encodeURI vs encodeURIComponent：何時用哪個？</title>
    <link href="https://kamadiam.com/encodeuri-vs-encodeuricomponent/" />
    <updated>2026-08-31T03:35:00Z</updated>
    <id>https://kamadiam.com/encodeuri-vs-encodeuricomponent/</id>
    <content type="html">&lt;p&gt;網址裡出現空格、&lt;code&gt;&amp;amp;&lt;/code&gt;、中文，瀏覽器常常會看不懂——就像信封地址寫「3 樓 &amp;amp; 4 樓」，郵差可能以為你要寄兩戶。JavaScript 有兩個長得很像的函式：&lt;code&gt;encodeURI&lt;/code&gt; 和 &lt;code&gt;encodeURIComponent&lt;/code&gt;。名字只差一個 &lt;code&gt;Component&lt;/code&gt;，但用錯的後果，有時比咖啡潑在鍵盤上還難收拾。&lt;/p&gt;&lt;p&gt;**一句話答案：**要編碼「整條網址」用 &lt;code&gt;encodeURI&lt;/code&gt;；要編碼「網址裡某一塊的值」（查詢參數、路徑片段）用 &lt;code&gt;encodeURIComponent&lt;/code&gt;。不確定時，參數值幾乎永遠選後者。&lt;/p&gt;&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/encodeuri-vs-encodeuricomponent/#encodeURI-%E5%92%8C-encodeURIComponent-%E5%B7%AE%E5%9C%A8%E5%93%AA?&quot;&gt;encodeURI 和 encodeURIComponent 差在哪？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/encodeuri-vs-encodeuricomponent/#encodeURI-%E6%98%AF%E4%BB%80%E9%BA%BC%E6%99%82%E5%80%99%E7%94%A8%E7%9A%84?&quot;&gt;encodeURI 是什麼時候用的？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/encodeuri-vs-encodeuricomponent/#encodeURIComponent-%E6%98%AF%E4%BB%80%E9%BA%BC%E6%99%82%E5%80%99%E7%94%A8%E7%9A%84?&quot;&gt;encodeURIComponent 是什麼時候用的？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/encodeuri-vs-encodeuricomponent/#%E5%AF%A6%E6%88%B0%E7%B5%84%E6%9F%A5%E8%A9%A2%E5%AD%97%E4%B8%B2%E8%A9%B2%E6%80%8E%E9%BA%BC%E5%AF%AB?&quot;&gt;實戰：組查詢字串該怎麼寫？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/encodeuri-vs-encodeuricomponent/#%E5%B8%B8%E8%A6%8B%E8%B8%A9%E9%9B%B7%E4%BB%80%E9%BA%BC%E6%99%82%E5%80%99%E6%9C%83%E7%94%A8%E9%8C%AF?&quot;&gt;常見踩雷：什麼時候會用錯？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/encodeuri-vs-encodeuricomponent/#%E5%BF%AB%E9%80%9F%E6%B1%BA%E7%AD%96%E6%88%91%E7%8F%BE%E5%9C%A8%E8%A9%B2%E7%94%A8%E5%93%AA%E5%80%8B?&quot;&gt;快速決策：我現在該用哪個？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/encodeuri-vs-encodeuricomponent/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;encodeURI-和-encodeURIComponent-差在哪?&quot;&gt;encodeURI 和 encodeURIComponent 差在哪？&lt;/h2&gt;&lt;p&gt;想像你在寫地址：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;encodeURI&lt;/code&gt;&lt;/strong&gt;：整條地址一起處理，但會保留 &lt;code&gt;: / ? &amp;amp; #&lt;/code&gt; 這些「路標」——它們是網址結構的一部分，不能亂改。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;encodeURIComponent&lt;/code&gt;&lt;/strong&gt;：只處理「包裹裡的內容」，把 &lt;code&gt;&amp;amp;&lt;/code&gt;、&lt;code&gt;=&lt;/code&gt;、&lt;code&gt;/&lt;/code&gt; 等特殊字元全部轉成 &lt;code&gt;%XX&lt;/code&gt;，避免破壞外層網址結構。&lt;/li&gt;&lt;/ul&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;比較項目&lt;/th&gt;&lt;th&gt;&lt;code&gt;encodeURI&lt;/code&gt;&lt;/th&gt;&lt;th&gt;&lt;code&gt;encodeURIComponent&lt;/code&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;編碼對象&lt;/td&gt;&lt;td&gt;完整 URI&lt;/td&gt;&lt;td&gt;單一 URI 組件（參數值、路徑段等）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;轉義範圍&lt;/td&gt;&lt;td&gt;只轉「不該出現在 URI 裡」的字元&lt;/td&gt;&lt;td&gt;轉義幾乎所有在 URI 有特殊意義的字元&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;會保留的字元&lt;/td&gt;&lt;td&gt;&lt;code&gt;:&lt;/code&gt;、&lt;code&gt;/&lt;/code&gt;、&lt;code&gt;?&lt;/code&gt;、&lt;code&gt;&amp;amp;&lt;/code&gt;、&lt;code&gt;#&lt;/code&gt; 等結構符號&lt;/td&gt;&lt;td&gt;無（結構符號也會被編碼）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;典型用途&lt;/td&gt;&lt;td&gt;整條網址字串需要編碼時&lt;/td&gt;&lt;td&gt;查詢參數的值、路徑片段、要嵌進 URL 的字串&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h2 id=&quot;encodeURI-是什麼時候用的?&quot;&gt;encodeURI 是什麼時候用的？&lt;/h2&gt;&lt;p&gt;&lt;code&gt;encodeURI&lt;/code&gt; 適合處理&lt;strong&gt;已經長得像完整網址&lt;/strong&gt;的字串，例如使用者輸入的 URL 裡有空格或中文，你要讓它變成合法 URI，但不想把 &lt;code&gt;https://&lt;/code&gt; 裡的 &lt;code&gt;:&lt;/code&gt; 和 &lt;code&gt;/&lt;/code&gt; 也編掉。&lt;/p&gt;&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;encodeURI&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://www.example.com/my page?name=John Doe&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &quot;https://www.example.com/my%20page?name=John%20Doe&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;空格變成 &lt;code&gt;%20&lt;/code&gt;，但 &lt;code&gt;?&lt;/code&gt;、&lt;code&gt;=&lt;/code&gt; 還在——因為它們是查詢字串的結構。問題也出在這裡：如果 &lt;code&gt;name&lt;/code&gt; 的值本身含有 &lt;code&gt;&amp;amp;&lt;/code&gt; 或 &lt;code&gt;=&lt;/code&gt;，&lt;code&gt;encodeURI&lt;/code&gt; &lt;strong&gt;不會&lt;/strong&gt;幫你保護這些字元，伺服器可能會誤讀參數。&lt;/p&gt;&lt;h2 id=&quot;encodeURIComponent-是什麼時候用的?&quot;&gt;encodeURIComponent 是什麼時候用的？&lt;/h2&gt;&lt;p&gt;&lt;code&gt;encodeURIComponent&lt;/code&gt; 把一段文字當成「要塞進網址某個位置的值」，所以特殊字元一律編碼，避免跟網址語法打架。&lt;/p&gt;&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;name=John Doe&amp;amp;age=30&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &quot;name%3DJohn%20Doe%26age%3D30&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;=&lt;/code&gt; 變 &lt;code&gt;%3D&lt;/code&gt;，&lt;code&gt;&amp;amp;&lt;/code&gt; 變 &lt;code&gt;%26&lt;/code&gt;，空格變 &lt;code&gt;%20&lt;/code&gt;。這就是為什麼組查詢字串時，&lt;strong&gt;每個參數的值&lt;/strong&gt;都應該各自包一層 &lt;code&gt;encodeURIComponent&lt;/code&gt;。&lt;/p&gt;&lt;h2 id=&quot;實戰組查詢字串該怎麼寫?&quot;&gt;實戰：組查詢字串該怎麼寫？&lt;/h2&gt;&lt;p&gt;下面用同一組資料示範兩種寫法：&lt;/p&gt;&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;John Doe&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; age &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://www.example.com/search&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 方法一：整段丟進 encodeURI（查詢參數不推薦）&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; badUrl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;encodeURI&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;url&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;?name=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;amp;age=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;age&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &quot;https://www.example.com/search?name=John%20Doe&amp;amp;age=30&quot;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// 簡單案例看起來沒事，但 name 若含 &amp;amp; 就會炸&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 方法二：只對參數值 encodeURIComponent（推薦）&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; goodUrl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;url&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;?name=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;amp;age=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;age&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &quot;https://www.example.com/search?name=John%20Doe&amp;amp;age=30&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;兩種寫法在 &lt;code&gt;name = &amp;quot;John Doe&amp;quot;&lt;/code&gt; 時結果一樣。差別在「值裡有沒有特殊字元」：&lt;/p&gt;&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tricky &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;John &amp;amp; Jane&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;encodeURI&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;url&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;?name=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;tricky&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &quot;https://www.example.com/search?name=John%20&amp;amp;%20Jane&quot;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &amp;amp; 沒被編碼 → 伺服器可能以為有兩個參數&lt;/span&gt;

&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;url&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;?name=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tricky&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &quot;https://www.example.com/search?name=John%20%26%20Jane&quot;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &amp;amp; 變 %26 → 安全&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;現代專案也可以直接用 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;URLSearchParams&lt;/code&gt;&lt;/a&gt;，它會幫你處理編碼，少手動拼接：&lt;/p&gt;&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; params &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URLSearchParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; tricky&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;age&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; safeUrl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;url&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;params&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &quot;https://www.example.com/search?name=John+%26+Jane&amp;amp;age=30&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;+&lt;/code&gt; 和 &lt;code&gt;%20&lt;/code&gt; 在查詢字串裡語意相近；重點是特殊字元不會再破壞結構。&lt;/p&gt;&lt;h2 id=&quot;常見踩雷什麼時候會用錯?&quot;&gt;常見踩雷：什麼時候會用錯？&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;用 &lt;code&gt;encodeURI&lt;/code&gt; 包查詢參數的值&lt;/strong&gt;：參數含 &lt;code&gt;&amp;amp;&lt;/code&gt;、&lt;code&gt;=&lt;/code&gt;、&lt;code&gt;#&lt;/code&gt; 時，網址可能被截斷或解析錯誤。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;對整條網址用 &lt;code&gt;encodeURIComponent&lt;/code&gt;&lt;/strong&gt;：&lt;code&gt;https://&lt;/code&gt; 會變成 &lt;code&gt;https%3A%2F%2F&lt;/code&gt;，瀏覽器打不開。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;重複編碼&lt;/strong&gt;：已經 &lt;code&gt;%20&lt;/code&gt; 的字串再 encode 一次，會變 &lt;code&gt;%2520&lt;/code&gt;，搜尋或導頁就對不上。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;忘記解碼&lt;/strong&gt;：讀取時用 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;decodeURIComponent&lt;/code&gt;&lt;/a&gt; 還原；&lt;code&gt;URLSearchParams.get()&lt;/code&gt; 會自動解碼。&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;快速決策我現在該用哪個?&quot;&gt;快速決策：我現在該用哪個？&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;情境&lt;/th&gt;&lt;th&gt;用哪個&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;整條 URL 有空格或中文，但結構已正確&lt;/td&gt;&lt;td&gt;&lt;code&gt;encodeURI&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;查詢參數的 key 或 value&lt;/td&gt;&lt;td&gt;&lt;code&gt;encodeURIComponent&lt;/code&gt;（或 &lt;code&gt;URLSearchParams&lt;/code&gt;）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;路徑片段（例如 &lt;code&gt;/users/王小明&lt;/code&gt; 裡的名字）&lt;/td&gt;&lt;td&gt;&lt;code&gt;encodeURIComponent&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;要把一段文字嵌進 &lt;code&gt;?q=&lt;/code&gt; 後面&lt;/td&gt;&lt;td&gt;&lt;code&gt;encodeURIComponent&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;不確定&lt;/td&gt;&lt;td&gt;參數值 → &lt;code&gt;encodeURIComponent&lt;/code&gt;；整條 URL → &lt;code&gt;encodeURI&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;hr&gt;&lt;p&gt;網址編碼這件事，本質就是「哪些字元是地址本身，哪些只是包裹裡的內容」。記住這個分工，&lt;code&gt;encodeURI&lt;/code&gt; 和 &lt;code&gt;encodeURIComponent&lt;/code&gt; 就不會再讓你半夜 debug 404 了——除非你真的把咖啡打翻在鍵盤上，那 AI 也救不了。&lt;/p&gt;&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;encodeURI() — MDN&lt;/a&gt;：&lt;code&gt;encodeURI&lt;/code&gt; 保留與不保留的字元清單&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;encodeURIComponent() — MDN&lt;/a&gt;：&lt;code&gt;encodeURIComponent&lt;/code&gt; 行為與範例&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;URLSearchParams — MDN&lt;/a&gt;：現代瀏覽器組查詢字串的建議做法&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc3986&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;RFC 3986 — URI Generic Syntax&lt;/a&gt;：URI 字元集與 percent-encoding 的規格來源&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Eleventy 怎麼顯示流程圖，Mermaid 的顯示和優化</title>
    <link href="https://kamadiam.com/eleventy-mermaid-static-images/" />
    <updated>2026-08-29T11:38:00Z</updated>
    <id>https://kamadiam.com/eleventy-mermaid-static-images/</id>
    <content type="html">&lt;p&gt;Mermaid 很方便：寫幾行文字，就能變成流程圖。問題是，如果每頁都把 Mermaid library 一起送到瀏覽器，讀者可能只是來看一篇文章，卻先搬一箱 JavaScript 回家。&lt;/p&gt;&lt;p&gt;文章中的流程圖、架構圖通常不需要訪客現場編輯或互動。這類圖適合用 Mermaid CLI 在建置前轉成靜態檔，再用 &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; 顯示——不用每頁載入 Mermaid JavaScript，Vite bundle 也不會因固定圖變胖，還能用 &lt;code&gt;alt&lt;/code&gt;、&lt;code&gt;width&lt;/code&gt;、&lt;code&gt;height&lt;/code&gt; 和 &lt;code&gt;&amp;lt;figcaption&amp;gt;&lt;/code&gt; 照顧可讀性與版面穩定。如果圖真的會跟著訪客操作即時變化，才保留瀏覽器端 Mermaid。&lt;/p&gt;&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/eleventy-mermaid-static-images/#SVGPNG,%E9%82%84%E6%98%AF%E7%80%8F%E8%A6%BD%E5%99%A8%E7%AB%AF-Mermaid?&quot;&gt;SVG、PNG，還是瀏覽器端 Mermaid？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/eleventy-mermaid-static-images/#%E7%AC%AC%E4%B8%80%E6%AD%A5%E6%BA%96%E5%82%99-Mermaid-%E5%8E%9F%E5%A7%8B%E6%AA%94&quot;&gt;第一步：準備 Mermaid 原始檔&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/eleventy-mermaid-static-images/#%E7%AC%AC%E4%BA%8C%E6%AD%A5%E7%94%A8-Mermaid-CLI-%E5%8C%AF%E5%87%BA-SVG-%E6%88%96-PNG&quot;&gt;第二步：用 Mermaid CLI 匯出 SVG 或 PNG&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/eleventy-mermaid-static-images/#%E7%AC%AC%E4%B8%89%E6%AD%A5%E8%AE%93-Eleventy-%E8%A4%87%E8%A3%BD%E5%9C%96%E6%AA%94%E4%B8%A6%E5%B5%8C%E5%85%A5%E9%A0%81%E9%9D%A2&quot;&gt;第三步：讓 Eleventy 複製圖檔並嵌入頁面&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/eleventy-mermaid-static-images/#%E7%AC%AC%E5%9B%9B%E6%AD%A5%E8%AE%93%E5%9C%96%E7%89%87%E5%9C%A8%E6%89%8B%E6%A9%9F%E4%B8%8A%E4%B8%8D%E6%8B%86%E5%8F%B0&quot;&gt;第四步：讓圖片在手機上不拆台&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/eleventy-mermaid-static-images/#%E4%B8%8A%E7%B7%9A%E5%89%8D%E6%AA%A2%E6%9F%A5%E6%B8%85%E5%96%AE&quot;&gt;上線前檢查清單&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/eleventy-mermaid-static-images/#%E7%B5%90%E8%AA%9E&quot;&gt;結語&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/eleventy-mermaid-static-images/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;SVGPNG,還是瀏覽器端-Mermaid?&quot;&gt;SVG、PNG，還是瀏覽器端 Mermaid？&lt;/h2&gt;&lt;p&gt;先看圖的用途，不要先看工具名稱。選錯格式，就像拿海報字體去印名片：不是不能用，只是會有點委屈。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;情境&lt;/th&gt;&lt;th&gt;建議&lt;/th&gt;&lt;th&gt;取捨&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;一般流程圖、架構圖&lt;/td&gt;&lt;td&gt;build-time SVG&lt;/td&gt;&lt;td&gt;線條與文字縮放清楚；仍要檢查文字大小與對比&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;固定像素圖片、社群分享、不想處理 SVG&lt;/td&gt;&lt;td&gt;build-time PNG&lt;/td&gt;&lt;td&gt;瀏覽器處理單純；放大可能變糊，檔案也可能較大&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;圖會因操作即時改變&lt;/td&gt;&lt;td&gt;瀏覽器端 Mermaid&lt;/td&gt;&lt;td&gt;保留互動，但要負擔下載、解析與執行 JavaScript&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;想把圖直接放進 HTML&lt;/td&gt;&lt;td&gt;build-time inline SVG&lt;/td&gt;&lt;td&gt;少一次圖片請求；HTML 變大，也要審查 SVG 內容&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;多數教學文章先選 SVG。若你的分享流程、圖片處理或內容系統更適合 PNG，也可以在同一次 build 產出 PNG。重點不是「PNG 永遠比較快」，而是不要讓每個頁面都執行整套繪圖 library。&lt;/p&gt;&lt;p&gt;若 Vite 出現 chunk 過大警告，先確認是不是 Mermaid 造成的。&lt;code&gt;build.chunkSizeWarningLimit&lt;/code&gt; 預設 500 kB，只是警告門檻，調高只會讓終端機安靜，不會讓下載變快。固定圖改走 build-time 匯出；只有少數頁面需要互動圖時，再用 &lt;code&gt;import(&#39;mermaid&#39;)&lt;/code&gt; 延遲載入並限制在需要的頁面。最後用 Network 和 Lighthouse 確認：不看圖的頁面，不應再載入 Mermaid chunk。&lt;/p&gt;&lt;h2 id=&quot;第一步準備-Mermaid-原始檔&quot;&gt;第一步：準備 Mermaid 原始檔&lt;/h2&gt;&lt;p&gt;例如建立 &lt;code&gt;src/diagrams/publish-flow.mmd&lt;/code&gt;：&lt;/p&gt;&lt;pre class=&quot;language-mermaid&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-mermaid&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;flowchart&lt;/span&gt; TD
  A&lt;span class=&quot;token text string&quot;&gt;[寫文章]&lt;/span&gt; &lt;span class=&quot;token arrow operator&quot;&gt;--&gt;&lt;/span&gt; B&lt;span class=&quot;token text string&quot;&gt;{檢查}&lt;/span&gt;
  B &lt;span class=&quot;token arrow operator&quot;&gt;--&gt;&lt;/span&gt;&lt;span class=&quot;token label property&quot;&gt;|通過|&lt;/span&gt; C&lt;span class=&quot;token text string&quot;&gt;[Eleventy build]&lt;/span&gt;
  B &lt;span class=&quot;token arrow operator&quot;&gt;--&gt;&lt;/span&gt;&lt;span class=&quot;token label property&quot;&gt;|未通過|&lt;/span&gt; A
  C &lt;span class=&quot;token arrow operator&quot;&gt;--&gt;&lt;/span&gt; D&lt;span class=&quot;token text string&quot;&gt;[輸出靜態網站]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;.mmd&lt;/code&gt; 是圖表的原始碼。它像食譜；SVG 或 PNG 才是端上桌的蛋糕。讀者通常只需要蛋糕，不需要一起下載烤箱。&lt;/p&gt;&lt;h2 id=&quot;第二步用-Mermaid-CLI-匯出-SVG-或-PNG&quot;&gt;第二步：用 Mermaid CLI 匯出 SVG 或 PNG&lt;/h2&gt;&lt;p&gt;Mermaid 官方 CLI 的套件名稱是 &lt;code&gt;@mermaid-js/mermaid-cli&lt;/code&gt;，命令名稱是 &lt;code&gt;mmdc&lt;/code&gt;。可以全域安裝：&lt;/p&gt;&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; @mermaid-js/mermaid-cli
mmdc &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;src/diagrams/publish-flow.mmd&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;src/assets/diagrams/publish-flow.svg&quot;&lt;/span&gt;
mmdc &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;src/diagrams/publish-flow.mmd&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;src/assets/diagrams/publish-flow.png&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;或者裝在專案內，讓本機和 CI 使用同一套依賴：&lt;/p&gt;&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; --save-dev @mermaid-js/mermaid-cli
./node_modules/.bin/mmdc &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;src/diagrams/publish-flow.mmd&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;src/assets/diagrams/publish-flow.svg&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;mmdc&lt;/code&gt; 會依輸出副檔名產生 SVG、PNG 或 PDF。也可以在輸出時指定主題與透明背景：&lt;/p&gt;&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;mmdc &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; input.mmd &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; output.png &lt;span class=&quot;token parameter variable&quot;&gt;-t&lt;/span&gt; dark &lt;span class=&quot;token parameter variable&quot;&gt;-b&lt;/span&gt; transparent&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;網站有深色模式時要多留意：SVG 能縮放，不代表它會自動換成深色配色。需要時在 build 時產生 light／dark 兩份，或固定一套在兩種背景都看得清楚的主題。&lt;/p&gt;&lt;h2 id=&quot;第三步讓-Eleventy-複製圖檔並嵌入頁面&quot;&gt;第三步：讓 Eleventy 複製圖檔並嵌入頁面&lt;/h2&gt;&lt;p&gt;如果圖片放在 &lt;code&gt;src/assets/diagrams/&lt;/code&gt;，在 &lt;code&gt;eleventy.config.js&lt;/code&gt; 加入 passthrough copy：&lt;/p&gt;&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;eleventyConfig&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addPassthroughCopy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;src/assets/diagrams&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;assets/diagrams&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;這會把來源目錄複製到輸出目錄的 &lt;code&gt;assets/diagrams&lt;/code&gt;。接著，文章或模板可以用普通 HTML 顯示圖片：&lt;/p&gt;&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;figure&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;diagram&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/assets/diagrams/publish-flow.svg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;發布流程：寫文章後先檢查；通過才執行 Eleventy build，失敗則回到修改文章。&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;900&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;520&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;decoding&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;async&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;figcaption&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;圖一：文章從檢查到 Eleventy build 的流程。&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;figcaption&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;figure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果 Markdown 設定允許原始 HTML，直接放上面的 &lt;code&gt;&amp;lt;figure&amp;gt;&lt;/code&gt; 即可。這裡要放的是 &lt;code&gt;&amp;lt;img src=&amp;quot;...&amp;quot;&amp;gt;&lt;/code&gt;，不是 &lt;code&gt;&amp;lt;div class=&amp;quot;mermaid&amp;quot;&amp;gt;&lt;/code&gt;。後者只是標記，仍需要 Mermaid JavaScript 在瀏覽器把它畫出來。&lt;/p&gt;&lt;p&gt;若 Markdown 會過濾 HTML，可改用 Nunjucks／WebC layout 或 shortcode 輸出同一段 HTML。不要為了繞過過濾器，就把所有內容無條件標成 &lt;code&gt;safe&lt;/code&gt;。&lt;/p&gt;&lt;p&gt;&lt;code&gt;alt&lt;/code&gt; 應描述讀者從圖中需要知道的結論或流程，不要只寫「流程圖」。如果正文已完整說明同一個流程，圖片可以用 &lt;code&gt;alt=&amp;quot;&amp;quot;&lt;/code&gt;，避免螢幕閱讀器重複朗讀——但正文不能因此消失。不要只靠顏色區分成功與失敗；把差異寫在節點文字、箭頭標籤或正文裡。&lt;/p&gt;&lt;h2 id=&quot;第四步讓圖片在手機上不拆台&quot;&gt;第四步：讓圖片在手機上不拆台&lt;/h2&gt;&lt;p&gt;圖片 CSS 可以先從這個版本開始：&lt;/p&gt;&lt;pre class=&quot;language-css&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.diagram&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2rem 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.diagram img&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.diagram figcaption&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;margin-top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--muted&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #666&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;width&lt;/code&gt; 和 &lt;code&gt;height&lt;/code&gt; 要填輸出圖片的實際像素尺寸。瀏覽器可以先依比例保留空間，降低圖片載入時內容跳動；如果比例填錯，反而可能失真或預留錯誤空間。&lt;/p&gt;&lt;p&gt;寬流程圖在手機上常見兩種結果：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;圖縮到看不清楚：改成較短的縱向流程。&lt;/li&gt;&lt;li&gt;圖不能再縮：提供原尺寸圖片連結，讓讀者自行放大查看。&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;如果有不同寬度或解析度版本，再考慮 &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; 和 &lt;code&gt;srcset&lt;/code&gt;。不要把一張超大 PNG 無條件送給所有裝置。&lt;/p&gt;&lt;h2 id=&quot;上線前檢查清單&quot;&gt;上線前檢查清單&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;[ ] &lt;code&gt;.mmd&lt;/code&gt; 與輸出的圖片都有納入版本控制，或 build 能穩定重建。&lt;/li&gt;&lt;li&gt;[ ] &lt;code&gt;mmdc&lt;/code&gt; 固定在專案 dev dependency，避免 CI 和本機產出不同。&lt;/li&gt;&lt;li&gt;[ ] 輸出路徑與 &lt;code&gt;&amp;lt;img src&amp;gt;&lt;/code&gt; 在開發伺服器、正式站與子路徑部署都正確。&lt;/li&gt;&lt;li&gt;[ ] Light／dark mode 下文字與背景都有足夠對比。&lt;/li&gt;&lt;li&gt;[ ] build 後確認不看圖的頁面沒有載入 Mermaid chunk。&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;結語&quot;&gt;結語&lt;/h2&gt;&lt;p&gt;固定圖先匯出，互動圖才在需要時載入 Mermaid。下一次新增 Mermaid 圖時，用 &lt;code&gt;mmdc&lt;/code&gt; 產出 SVG 或 PNG，放進 Eleventy 的 passthrough asset，再用帶有 &lt;code&gt;alt&lt;/code&gt;、尺寸和圖說的 &lt;code&gt;&amp;lt;figure&amp;gt;&lt;/code&gt; 顯示。先改一張圖，再看 build 與 Network 數據。&lt;/p&gt;&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/mermaid-js/mermaid-cli/blob/master/README.md&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Mermaid CLI 官方 README&lt;/a&gt; — 官方 CLI 安裝、&lt;code&gt;mmdc&lt;/code&gt; 參數，以及 SVG／PNG／PDF 輸出。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://mermaid.js.org/config/mermaidCLI.html&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Mermaid CLI 官方文件入口&lt;/a&gt; — Mermaid CLI 文件入口。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/copy/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Eleventy Passthrough File Copy&lt;/a&gt; — &lt;code&gt;addPassthroughCopy&lt;/code&gt; 的來源與輸出路徑。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://vite.dev/config/build-options&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Vite Build Options&lt;/a&gt; — &lt;code&gt;chunkSizeWarningLimit&lt;/code&gt; 的預設值與用途。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/figure&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;MDN：&lt;code&gt;&amp;lt;figure&amp;gt;&lt;/code&gt;&lt;/a&gt; — &lt;code&gt;figure&lt;/code&gt;、&lt;code&gt;figcaption&lt;/code&gt; 與語意結構。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Structuring_content/HTML_images&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;MDN：HTML images&lt;/a&gt; — &lt;code&gt;img&lt;/code&gt;、&lt;code&gt;alt&lt;/code&gt; 與圖片可及性。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Box_sizing/Aspect_ratios&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;MDN：Understanding and setting aspect ratios&lt;/a&gt; — 圖片尺寸與版面空間預留。&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>什麼是 PHP？入門指南：用途、市占與 vs Node.js／Python</title>
    <link href="https://kamadiam.com/what-is-php/" />
    <updated>2026-08-29T00:00:00Z</updated>
    <id>https://kamadiam.com/what-is-php/</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;PHP（PHP: Hypertext Preprocessor）&lt;/strong&gt; 是一種在&lt;strong&gt;伺服器端&lt;/strong&gt;執行的開源腳本語言，主要用來產生動態網頁。瀏覽器收到的是 PHP 執行後的 HTML；資料庫查詢、登入驗證、表單處理，多半在伺服器上完成，不會把原始碼直接送到使用者電腦。&lt;/p&gt;&lt;p&gt;「PHP 已死」這句話聽了十多年，但 &lt;a href=&quot;https://w3techs.com/technologies/details/pl-php&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;W3Techs&lt;/a&gt; 在 2026 年仍顯示約 &lt;strong&gt;70.5%&lt;/strong&gt; 的已知伺服器端語言網站使用 PHP；&lt;a href=&quot;https://w3techs.com/technologies/comparison/cm-wordpress&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;WordPress&lt;/a&gt; 約佔全站 &lt;strong&gt;41.2%&lt;/strong&gt;。若你的目標是架站、維護 CMS 或接 Laravel 後端，PHP 仍是務實選項。&lt;/p&gt;&lt;h2 id=&quot;快速參考&quot;&gt;快速參考&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;項目&lt;/th&gt;&lt;th&gt;說明&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;PHP 是什麼&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;伺服器端腳本語言，在伺服器產生 HTML 再送給瀏覽器&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;常見用途&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;WordPress／Drupal、電商、REST API、表單與檔案處理&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;還值得學嗎&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;架站、CMS、Laravel 路線 → 是；AI／資料科學主力 → 優先 Python&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;vs Node.js&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;PHP 強在 CMS 生態；Node 強在即時 API 與 JavaScript 全端&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;怎麼開始&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://kamadiam.com/what-is-herd/&quot;&gt;Herd&lt;/a&gt; 或 &lt;code&gt;php -S&lt;/code&gt; + &lt;a href=&quot;https://kamadiam.com/php-basic-tutorial/&quot;&gt;PHP 新手入門&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/what-is-php/#%E5%BF%AB%E9%80%9F%E5%8F%83%E8%80%83&quot;&gt;快速參考&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/what-is-php/#PHP-%E7%9A%84%E7%94%A8%E9%80%94%E5%B7%A5%E7%A8%8B%E5%B8%AB%E5%AF%A6%E9%9A%9B%E5%9C%A8%E5%81%9A%E4%BB%80%E9%BA%BC?&quot;&gt;PHP 的用途：工程師實際在做什麼？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/what-is-php/#%E6%9C%80%E5%B0%8F%E7%AF%84%E4%BE%8B5-%E5%88%86%E9%90%98%E8%B7%91%E8%B5%B7%E4%BE%86&quot;&gt;最小範例：5 分鐘跑起來&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/what-is-php/#%E7%82%BA%E4%BB%80%E9%BA%BC%E9%82%84%E6%9C%89%E4%BA%BA%E7%94%A8-PHP?&quot;&gt;為什麼還有人用 PHP？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/what-is-php/#PHP-vs-Node.js-vs-Python%E6%80%8E%E9%BA%BC%E9%81%B8&quot;&gt;PHP vs Node.js vs Python：怎麼選&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/what-is-php/#PHP-8.x-%E4%BD%A0%E8%A9%B2%E7%9F%A5%E9%81%93%E7%9A%84%E6%96%B0%E7%89%B9%E6%80%A7&quot;&gt;PHP 8.x 你該知道的新特性&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/what-is-php/#%E6%80%8E%E9%BA%BC%E9%96%8B%E5%A7%8B%E7%92%B0%E5%A2%83%E8%88%87%E5%AD%B8%E7%BF%92%E8%B7%AF%E5%BE%91&quot;&gt;怎麼開始：環境與學習路徑&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/what-is-php/#%E5%B8%B8%E8%A6%8B%E5%95%8F%E9%A1%8C&quot;&gt;常見問題&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/what-is-php/#%E7%B5%90%E8%AA%9E&quot;&gt;結語&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/what-is-php/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;PHP-的用途工程師實際在做什麼?&quot;&gt;PHP 的用途：工程師實際在做什麼？&lt;/h2&gt;&lt;p&gt;PHP 工程師的典型工作包含：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;後端業務邏輯、資料庫設計與查詢&lt;/li&gt;&lt;li&gt;REST API、Webhook、第三方服務整合&lt;/li&gt;&lt;li&gt;WordPress 主題／外掛，或 Laravel／Symfony 應用&lt;/li&gt;&lt;li&gt;效能調校、資安（XSS、CSRF、SQL Injection）與部署維運&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;實務技能組合：&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;PHP 8 + &lt;a href=&quot;https://kamadiam.com/php-composer-intro/&quot;&gt;Composer&lt;/a&gt; 依賴管理&lt;/li&gt;&lt;li&gt;SQL（MySQL／MariaDB／PostgreSQL）&lt;/li&gt;&lt;li&gt;HTTP、REST、基本資安&lt;/li&gt;&lt;li&gt;Git&lt;/li&gt;&lt;li&gt;至少一種框架或 CMS（Laravel 或 WordPress）&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;職涯方向可往資深後端、全端、技術主管或接案維護站發展。台灣職缺可在 104 等平台搜「PHP」「Laravel」「WordPress」比對當下行情。&lt;/p&gt;&lt;h2 id=&quot;最小範例5-分鐘跑起來&quot;&gt;最小範例：5 分鐘跑起來&lt;/h2&gt;&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token php language-php&quot;&gt;&lt;span class=&quot;token delimiter important&quot;&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;h1&gt;Hello PHP&amp;lt;/h1&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;存成 &lt;code&gt;index.php&lt;/code&gt;，用內建伺服器執行：&lt;/p&gt;&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;php &lt;span class=&quot;token parameter variable&quot;&gt;-S&lt;/span&gt; localhost:8000&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;開啟 &lt;code&gt;http://localhost:8000&lt;/code&gt; 就是最小的動態網頁。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;和瀏覽器 JavaScript 的差別：&lt;/strong&gt;&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;PHP&lt;/th&gt;&lt;th&gt;瀏覽器端 JavaScript&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;執行位置&lt;/td&gt;&lt;td&gt;伺服器&lt;/td&gt;&lt;td&gt;使用者裝置／瀏覽器&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;典型工作&lt;/td&gt;&lt;td&gt;資料庫、權限、API、產生 HTML&lt;/td&gt;&lt;td&gt;互動、動畫、SPA&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;部署&lt;/td&gt;&lt;td&gt;虛擬主機／VPS／容器皆常見&lt;/td&gt;&lt;td&gt;隨頁面下載&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;JavaScript 也能在後端跑（Node.js），所以「語言名稱 ≠ 前後端」；PHP 則主要以網站後端與伺服器端腳本為人熟知。&lt;/p&gt;&lt;h2 id=&quot;為什麼還有人用-PHP?&quot;&gt;為什麼還有人用 PHP？&lt;/h2&gt;&lt;h3 id=&quot;市占與生態&quot;&gt;市占與生態&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;伺服器端語言&lt;/strong&gt;：PHP 約 &lt;strong&gt;70.5%&lt;/strong&gt;（W3Techs，2026-08）&lt;/li&gt;&lt;li&gt;&lt;strong&gt;CMS&lt;/strong&gt;：WordPress 約佔全站 &lt;strong&gt;41.2%&lt;/strong&gt;（W3Techs，2026-08）&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;這些是會每日變動的調查數字，分母是「被 W3Techs 辨識出來的網站」，不是整個網路的戶口普查。市占高不代表「最適合每個專案」，但代表主機支援、外掛、教學、接案需求都還在。&lt;/p&gt;&lt;h3 id=&quot;主機與上線成本&quot;&gt;主機與上線成本&lt;/h3&gt;&lt;p&gt;許多虛擬主機提供 PHP 與資料庫，部署傳統網站不必先組一整套應用程式平台。延伸：&lt;a href=&quot;https://kamadiam.com/free-ssl-certificate/&quot;&gt;免費 SSL&lt;/a&gt;、&lt;a href=&quot;https://kamadiam.com/what-is-herd/&quot;&gt;Herd 本機環境&lt;/a&gt;。&lt;/p&gt;&lt;h3 id=&quot;現代-PHP-已不是「把-HTML-跟邏輯攪在一起」&quot;&gt;現代 PHP 已不是「把 HTML 跟邏輯攪在一起」&lt;/h3&gt;&lt;p&gt;PHP 8 系列加入 Named arguments、Union types、Attributes、Readonly 等現代語法。主流框架（Laravel、Symfony）搭配 Composer，讓大型專案比較容易維持結構。&lt;/p&gt;&lt;h3 id=&quot;什麼時候不該硬選-PHP&quot;&gt;什麼時候不該硬選 PHP&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;即時協作、WebSocket 重度應用 → 可優先評估 Node.js&lt;/li&gt;&lt;li&gt;資料科學、機器學習主力 → 通常優先 Python&lt;/li&gt;&lt;li&gt;純靜態內容、極致效能與低維護 → &lt;a href=&quot;https://kamadiam.com/static-site-generators/&quot;&gt;靜態網站生成器&lt;/a&gt;／&lt;a href=&quot;https://kamadiam.com/11ty-generator/&quot;&gt;11ty&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;PHP-vs-Node.js-vs-Python怎麼選&quot;&gt;PHP vs Node.js vs Python：怎麼選&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;面向&lt;/th&gt;&lt;th&gt;PHP&lt;/th&gt;&lt;th&gt;Node.js&lt;/th&gt;&lt;th&gt;Python（Django／Flask）&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;架站／CMS&lt;/td&gt;&lt;td&gt;WordPress 生態成熟&lt;/td&gt;&lt;td&gt;常需自組或採 Headless&lt;/td&gt;&lt;td&gt;可，常見於 Django 等框架&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;共享主機支援&lt;/td&gt;&lt;td&gt;常見&lt;/td&gt;&lt;td&gt;取決於主機商&lt;/td&gt;&lt;td&gt;取決於主機商&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;即時應用&lt;/td&gt;&lt;td&gt;可做，非傳統強項&lt;/td&gt;&lt;td&gt;強&lt;/td&gt;&lt;td&gt;中&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;AI／資料分析&lt;/td&gt;&lt;td&gt;弱&lt;/td&gt;&lt;td&gt;中&lt;/td&gt;&lt;td&gt;強&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;學習曲線（網站）&lt;/td&gt;&lt;td&gt;低～中&lt;/td&gt;&lt;td&gt;中（非同步思維）&lt;/td&gt;&lt;td&gt;中&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;常見使用情境&lt;/td&gt;&lt;td&gt;CMS、傳統網站、後端&lt;/td&gt;&lt;td&gt;JavaScript 全端、即時服務&lt;/td&gt;&lt;td&gt;資料處理、後端、AI 原型&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;strong&gt;實務建議：&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;要維護或客製 WordPress、接中小企業站 → &lt;strong&gt;學 PHP&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;要做 SPA + API、即時功能 → &lt;strong&gt;Node.js&lt;/strong&gt;（或 PHP API + 前端框架）&lt;/li&gt;&lt;li&gt;要做資料管線、AI 原型 → &lt;strong&gt;Python&lt;/strong&gt;，網站可另選&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;PHP-8.x-你該知道的新特性&quot;&gt;PHP 8.x 你該知道的新特性&lt;/h2&gt;&lt;h3 id=&quot;PHP-8.0–8.3&quot;&gt;PHP 8.0–8.3&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Named arguments&lt;/strong&gt;、&lt;strong&gt;union types&lt;/strong&gt;、&lt;strong&gt;match&lt;/strong&gt;、&lt;strong&gt;attributes&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Constructor property promotion&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Readonly properties／classes&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;#[&#92;Override]&lt;/code&gt;&lt;/strong&gt;（8.3）&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;PHP-8.4–8.5-值得關注&quot;&gt;PHP 8.4–8.5 值得關注&lt;/h3&gt;&lt;p&gt;依 &lt;a href=&quot;https://www.php.net/releases/8_5_0.php&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PHP 8.5 官方發布公告&lt;/a&gt;：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Pipe operator &lt;code&gt;|&amp;gt;&lt;/code&gt;&lt;/strong&gt;：把巢狀呼叫改成由左到右的資料流&lt;/li&gt;&lt;li&gt;&lt;strong&gt;內建 URI extension&lt;/strong&gt;：依 RFC 3986／WHATWG 解析 URL&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;clone()&lt;/code&gt; 搭配屬性更新&lt;/strong&gt;：方便 readonly／value object 的 with-er 模式&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.php.net/manual/en/class.nodiscard.php&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;#[&#92;NoDiscard]&lt;/a&gt;&lt;/strong&gt;：提醒呼叫端不要忽略重要回傳值&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token php language-php&quot;&gt;&lt;span class=&quot;token delimiter important&quot;&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$result&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$input&lt;/span&gt;
	&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strtolower&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;htmlspecialchars&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;正式環境升級前，請對照框架支援與 &lt;a href=&quot;https://www.php.net/supported-versions.php&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PHP 官方支援版本表&lt;/a&gt;。PHP 7 已不在支援清單內，正式環境應規劃升級到 PHP 8.x。&lt;/p&gt;&lt;h2 id=&quot;怎麼開始環境與學習路徑&quot;&gt;怎麼開始：環境與學習路徑&lt;/h2&gt;&lt;h3 id=&quot;本機環境&quot;&gt;本機環境&lt;/h3&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;平台&lt;/th&gt;&lt;th&gt;建議&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;macOS&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://kamadiam.com/what-is-herd/&quot;&gt;Herd&lt;/a&gt;（最省事）或 &lt;a href=&quot;https://kamadiam.com/homebrew-tutorial/&quot;&gt;Homebrew&lt;/a&gt; &lt;code&gt;brew install php&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Windows&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://herd.laravel.com/windows&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Herd for Windows&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;只要試玩&lt;/td&gt;&lt;td&gt;官方二進位 + &lt;code&gt;php -S&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h3 id=&quot;五分鐘動態網頁範例&quot;&gt;五分鐘動態網頁範例&lt;/h3&gt;&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token php language-php&quot;&gt;&lt;span class=&quot;token delimiter important&quot;&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;declare&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;strict_types&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token variable&quot;&gt;$name&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$_GET&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;name&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;訪客&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token delimiter important&quot;&gt;?&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token doctype&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span class=&quot;token doctype-tag&quot;&gt;DOCTYPE&lt;/span&gt; &lt;span class=&quot;token name&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;html&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;lang&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;zh-Hant&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;charset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;UTF-8&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hello&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;你好，&lt;span class=&quot;token php language-php&quot;&gt;&lt;span class=&quot;token delimiter important&quot;&gt;&amp;lt;?=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;htmlspecialchars&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ENT_QUOTES&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;UTF-8&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token delimiter important&quot;&gt;?&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;重點習慣：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;開啟 &lt;code&gt;declare(strict_types=1);&lt;/code&gt;&lt;/li&gt;&lt;li&gt;輸出到 HTML 前做跳脫（防 XSS）&lt;/li&gt;&lt;li&gt;密碼用 &lt;code&gt;password_hash()&lt;/code&gt;／&lt;code&gt;password_verify()&lt;/code&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h3 id=&quot;建議學習順序&quot;&gt;建議學習順序&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;語法與陣列 → &lt;a href=&quot;https://kamadiam.com/php-basic-tutorial/&quot;&gt;PHP 新手入門練習&lt;/a&gt;&lt;/li&gt;&lt;li&gt;類別與物件 → &lt;a href=&quot;https://kamadiam.com/php-object-and-class/&quot;&gt;Class／Object&lt;/a&gt;、&lt;a href=&quot;https://kamadiam.com/php-access-modifiers/&quot;&gt;存取修飾符&lt;/a&gt;&lt;/li&gt;&lt;li&gt;例外處理 → &lt;a href=&quot;https://kamadiam.com/php-exception-handling/&quot;&gt;try catch&lt;/a&gt;&lt;/li&gt;&lt;li&gt;依賴管理 → &lt;a href=&quot;https://kamadiam.com/php-composer-intro/&quot;&gt;Composer&lt;/a&gt;&lt;/li&gt;&lt;li&gt;設計原則 → &lt;a href=&quot;https://kamadiam.com/solid-principles-in-php/&quot;&gt;SOLID&lt;/a&gt;&lt;/li&gt;&lt;li&gt;選一條產品路：WordPress 外掛／主題，或 Laravel 專案&lt;/li&gt;&lt;/ol&gt;&lt;h2 id=&quot;常見問題&quot;&gt;常見問題&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Q：PHP 是什麼語言？&lt;/strong&gt;&lt;br&gt;A：開源的伺服器端腳本語言，專為網頁開發設計，在伺服器執行後產生 HTML 等內容送給瀏覽器。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Q：現在才學 PHP 會不會過時？&lt;/strong&gt;&lt;br&gt;A：若目標是架站、WordPress、中小企業維護或 Laravel，PHP 仍是合理選項。若目標是 AI 研究，通常應以 Python 為主。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Q：一定要先學完 OOP 才能碰 WordPress 嗎？&lt;/strong&gt;&lt;br&gt;A：不必。可先做主題／小外掛建立回饋，再回頭補 &lt;a href=&quot;https://kamadiam.com/php-object-and-class/&quot;&gt;物件導向&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Q：和靜態站怎麼選？&lt;/strong&gt;&lt;br&gt;A：內容少、更新不頻繁、要極致速度與低維護 → 靜態站（本站即 &lt;a href=&quot;https://kamadiam.com/wordpress-vs-11ty/&quot;&gt;11ty&lt;/a&gt;）。要後台、會員、大量編輯者 → PHP／CMS 仍合理。&lt;/p&gt;&lt;h2 id=&quot;結語&quot;&gt;結語&lt;/h2&gt;&lt;p&gt;學 PHP 的理由很務實：&lt;strong&gt;生態還在、主機選擇多、WordPress／Laravel 仍有大量使用情境，語言本身也持續更新到 8.5&lt;/strong&gt;。先掌握「伺服器端動態網頁」這個心智模型，再依目標選 CMS 或框架，比糾結「哪種語言最潮」有用。&lt;/p&gt;&lt;p&gt;下一步：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;裝好環境（Herd 或 Homebrew）&lt;/li&gt;&lt;li&gt;跑完 &lt;a href=&quot;https://kamadiam.com/php-basic-tutorial/&quot;&gt;10 個 PHP 練習&lt;/a&gt;&lt;/li&gt;&lt;li&gt;決定路線：WordPress 實戰，或 Laravel 入門&lt;/li&gt;&lt;/ol&gt;&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/en/introduction.php&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PHP 官方手冊：Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.php.net/releases/8_5_0.php&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PHP 8.5.0 官方發布公告&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.php.net/supported-versions.php&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PHP 官方支援版本&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://w3techs.com/technologies/details/pl-php&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;W3Techs：PHP 使用統計&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://w3techs.com/technologies/comparison/cm-wordpress&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;W3Techs：WordPress 使用統計&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>TypeScript 入門教學：零基礎快速上手（tsc 安裝＋tsconfig 速查）</title>
    <link href="https://kamadiam.com/typescript-getting-started/" />
    <updated>2026-08-29T00:00:00Z</updated>
    <id>https://kamadiam.com/typescript-getting-started/</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;TypeScript&lt;/strong&gt; 是 JavaScript 的&lt;strong&gt;語法超集&lt;/strong&gt;：合法 JS 幾乎都能放進 &lt;code&gt;.ts&lt;/code&gt; 檔，同時多了&lt;strong&gt;型別系統&lt;/strong&gt;與編譯期檢查，讓錯誤在寫程式時就被抓出，而不是等到使用者按下按鈕才尖叫。瀏覽器與 Node.js 最終仍執行 JavaScript，所以 &lt;code&gt;.ts&lt;/code&gt; 通常要先經 &lt;strong&gt;TypeScript 編譯器（&lt;code&gt;tsc&lt;/code&gt;）&lt;/strong&gt; 轉成 JS 再執行——型別資訊留在開發階段，不會原封不動出現在輸出檔裡。&lt;/p&gt;&lt;p&gt;這篇帶你在 macOS 完成 &lt;strong&gt;TypeScript 入門&lt;/strong&gt;全流程：安裝 Node.js、&lt;code&gt;tsc&lt;/code&gt; 安裝、&lt;code&gt;tsconfig.json&lt;/code&gt; 設定、編譯第一支程式，並比較 Node.js、ts-node、Playground、Deno 與 Bun 幾種常見執行方式。&lt;/p&gt;&lt;h2 id=&quot;快速參考&quot;&gt;快速參考&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;項目&lt;/th&gt;&lt;th&gt;說明&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TypeScript 是什麼&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;JS 超集 + 靜態型別檢查，輸出仍是 JavaScript&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;tsc 安裝&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;npm install --save-dev typescript&lt;/code&gt;，執行用 &lt;code&gt;npx tsc&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;tsconfig 初始化&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;npx tsc --init&lt;/code&gt; 產生 &lt;code&gt;tsconfig.json&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;編譯專案&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;npx tsc&lt;/code&gt; → 輸出到 &lt;code&gt;dist/&lt;/code&gt;；只檢查型別：&lt;code&gt;npx tsc --noEmit&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;不想裝環境&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://www.typescriptlang.org/play&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;TypeScript Playground&lt;/a&gt; 線上試寫&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Node.js 安裝&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://kamadiam.com/homebrew-tutorial/&quot;&gt;Homebrew 教學&lt;/a&gt; 的 &lt;code&gt;brew install node&lt;/code&gt;，或 &lt;a href=&quot;https://nodejs.org/en/download&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;官方下載&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;替代執行環境&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;ts-node（開發腳本）、Deno／Bun（內建 TS 支援）&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/typescript-getting-started/#%E5%BF%AB%E9%80%9F%E5%8F%83%E8%80%83&quot;&gt;快速參考&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/typescript-getting-started/#TypeScript-%E6%98%AF%E4%BB%80%E9%BA%BC?&quot;&gt;TypeScript 是什麼？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/typescript-getting-started/#%E5%BB%BA%E7%AB%8B-TypeScript-%E9%96%8B%E7%99%BC%E7%92%B0%E5%A2%83&quot;&gt;建立 TypeScript 開發環境&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/typescript-getting-started/#%E5%AF%AB%E5%87%BA%E4%B8%A6%E7%B7%A8%E8%AD%AF%E7%AC%AC%E4%B8%80%E6%94%AF-TypeScript-%E7%A8%8B%E5%BC%8F&quot;&gt;寫出並編譯第一支 TypeScript 程式&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/typescript-getting-started/#tsc-%E5%B8%B8%E7%94%A8%E6%8C%87%E4%BB%A4&quot;&gt;tsc 常用指令&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/typescript-getting-started/#%E5%9F%B7%E8%A1%8C-TypeScript-%E7%9A%84%E5%B9%BE%E7%A8%AE%E6%96%B9%E5%BC%8F&quot;&gt;執行 TypeScript 的幾種方式&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/typescript-getting-started/#%E5%B8%B8%E8%A6%8B-FAQ&quot;&gt;常見 FAQ&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/typescript-getting-started/#%E6%8E%A5%E4%B8%8B%E4%BE%86%E5%8F%AF%E4%BB%A5%E5%AD%B8%E4%BB%80%E9%BA%BC?&quot;&gt;接下來可以學什麼？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/typescript-getting-started/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;TypeScript-是什麼?&quot;&gt;TypeScript 是什麼？&lt;/h2&gt;&lt;p&gt;一句話：&lt;strong&gt;TypeScript = JavaScript + 型別&lt;/strong&gt;。它不是把 JS 重新發明一遍，而是在你熟悉的語法上加上型別註記、&lt;code&gt;interface&lt;/code&gt;、泛型等工具，並由 &lt;code&gt;tsc&lt;/code&gt; 在編譯時檢查型別是否一致。&lt;/p&gt;&lt;p&gt;實務上，多數團隊會把 &lt;code&gt;.ts&lt;/code&gt; 編譯成目標環境能跑的 JS（例如 ES2022），再交給 Node.js 或打包工具處理。好處是重構時編譯器會提醒你哪裡漏改，IDE 也能提供更準確的自動完成——比靠 &lt;code&gt;console.log&lt;/code&gt; 考古快多了。&lt;/p&gt;&lt;h2 id=&quot;建立-TypeScript-開發環境&quot;&gt;建立 TypeScript 開發環境&lt;/h2&gt;&lt;p&gt;先裝 &lt;strong&gt;Node.js&lt;/strong&gt;，再在專案內安裝 TypeScript。把 &lt;code&gt;tsc&lt;/code&gt; 裝在專案裡（而非全域），版本比較好固定，也比較不會遇到「在我電腦明明可以」的經典劇情。&lt;/p&gt;&lt;h3 id=&quot;安裝-Node.js&quot;&gt;安裝 Node.js&lt;/h3&gt;&lt;p&gt;從 &lt;a href=&quot;https://nodejs.org/en/download&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Node.js 官方網站&lt;/a&gt; 下載，或用 &lt;a href=&quot;https://kamadiam.com/homebrew-tutorial/&quot;&gt;Homebrew&lt;/a&gt;：&lt;/p&gt;&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;確認可用：&lt;/p&gt;&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--version&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--version&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;安裝-TypeScripttsc&quot;&gt;安裝 TypeScript（tsc）&lt;/h3&gt;&lt;p&gt;建立專案並初始化：&lt;/p&gt;&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; typescript-demo
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; typescript-demo
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; init &lt;span class=&quot;token parameter variable&quot;&gt;-y&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;把 TypeScript 裝成開發依賴——這就是 &lt;strong&gt;&lt;code&gt;tsc&lt;/code&gt; 安裝&lt;/strong&gt;的標準做法：&lt;/p&gt;&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; --save-dev typescript&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;pnpm 使用者：&lt;/p&gt;&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;pnpm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; --save-dev typescript&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;專案內的 &lt;code&gt;tsc&lt;/code&gt; 不會自動變成全域命令，請透過 &lt;code&gt;npx&lt;/code&gt;（或 &lt;code&gt;pnpm exec&lt;/code&gt;）執行：&lt;/p&gt;&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;npx tsc &lt;span class=&quot;token parameter variable&quot;&gt;--version&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;初始化-tsconfig.json&quot;&gt;初始化 &lt;code&gt;tsconfig.json&lt;/code&gt;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;tsconfig.json&lt;/code&gt; 告訴編譯器要處理哪些檔案、輸出什麼格式的 JS。執行：&lt;/p&gt;&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;npx tsc &lt;span class=&quot;token parameter variable&quot;&gt;--init&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;入門可先採用這份精簡設定：&lt;/p&gt;&lt;pre class=&quot;language-json&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;&quot;compilerOptions&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token property&quot;&gt;&quot;target&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ES2022&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token property&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NodeNext&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token property&quot;&gt;&quot;moduleResolution&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NodeNext&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token property&quot;&gt;&quot;strict&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token property&quot;&gt;&quot;outDir&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;dist&quot;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token property&quot;&gt;&quot;include&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;src/**/*.ts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;重點三項：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;target&lt;/code&gt;：輸出的 JavaScript 語法版本&lt;/li&gt;&lt;li&gt;&lt;code&gt;module&lt;/code&gt; / &lt;code&gt;moduleResolution&lt;/code&gt;：依 Node.js 現代模組規則解析&lt;/li&gt;&lt;li&gt;&lt;code&gt;strict: true&lt;/code&gt;：開啟嚴格型別檢查，編譯期能抓出更多問題&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;實際專案會依 Node 版本與建置工具調整；上面這份適合作為現代 Node.js 的入門起點。&lt;/p&gt;&lt;h2 id=&quot;寫出並編譯第一支-TypeScript-程式&quot;&gt;寫出並編譯第一支 TypeScript 程式&lt;/h2&gt;&lt;p&gt;建立 &lt;code&gt;src/hello.ts&lt;/code&gt;：&lt;/p&gt;&lt;pre class=&quot;language-typescript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Hello, TypeScript!&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;編譯：&lt;/p&gt;&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;npx tsc&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;輸出會依照 &lt;code&gt;tsconfig.json&lt;/code&gt; 放到 &lt;code&gt;dist/&lt;/code&gt;。執行產生的 JS：&lt;/p&gt;&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; dist/hello.js&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;若把字串傳給需要數字的函式，&lt;code&gt;tsc&lt;/code&gt; 會在編譯時報錯——這就是型別檢查的價值，比執行時才發現少掉幾根頭髮。&lt;/p&gt;&lt;h2 id=&quot;tsc-常用指令&quot;&gt;&lt;code&gt;tsc&lt;/code&gt; 常用指令&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;指令&lt;/th&gt;&lt;th&gt;用途&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;npx tsc&lt;/code&gt;&lt;/td&gt;&lt;td&gt;依 &lt;code&gt;tsconfig.json&lt;/code&gt; 編譯整個專案&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;npx tsc --noEmit&lt;/code&gt;&lt;/td&gt;&lt;td&gt;只檢查型別、不產生輸出（適合 CI）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;npx tsc src/hello.ts&lt;/code&gt;&lt;/td&gt;&lt;td&gt;編譯單一檔案（可能不完全套用專案設定）&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;正式專案建議讓 &lt;code&gt;tsconfig.json&lt;/code&gt; 管理編譯範圍，執行不帶檔名的 &lt;code&gt;npx tsc&lt;/code&gt;，行為最一致。&lt;/p&gt;&lt;h2 id=&quot;執行-TypeScript-的幾種方式&quot;&gt;執行 TypeScript 的幾種方式&lt;/h2&gt;&lt;p&gt;完成編譯後，最單純的路線是 &lt;strong&gt;Node.js 跑輸出的 JS&lt;/strong&gt;。也有適合不同情境的工具——重點不是哪個最潮，而是哪個適合你的專案。&lt;/p&gt;&lt;h3 id=&quot;使用-Node.js&quot;&gt;使用 Node.js&lt;/h3&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/lBC9QFhBEe-240.webp 240w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/lBC9QFhBEe-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;240&quot; height=&quot;70&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;Node.js 執行的是 JavaScript。入門建議先 &lt;code&gt;tsc&lt;/code&gt; 編譯再執行：&lt;/p&gt;&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;npx tsc
&lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; dist/hello.js&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;使用-ts-node&quot;&gt;使用 ts-node&lt;/h3&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/39m0sj94DQ-240.webp 240w, https://kamadiam.com/img/built/39m0sj94DQ-320.webp 320w, https://kamadiam.com/img/built/39m0sj94DQ-480.webp 480w, https://kamadiam.com/img/built/39m0sj94DQ-640.webp 640w, https://kamadiam.com/img/built/39m0sj94DQ-672.webp 672w, https://kamadiam.com/img/built/39m0sj94DQ-800.webp 800w, https://kamadiam.com/img/built/39m0sj94DQ-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/39m0sj94DQ-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;455&quot; srcset=&quot;https://kamadiam.com/img/built/39m0sj94DQ-240.png 240w, https://kamadiam.com/img/built/39m0sj94DQ-320.png 320w, https://kamadiam.com/img/built/39m0sj94DQ-480.png 480w, https://kamadiam.com/img/built/39m0sj94DQ-640.png 640w, https://kamadiam.com/img/built/39m0sj94DQ-672.png 672w, https://kamadiam.com/img/built/39m0sj94DQ-800.png 800w, https://kamadiam.com/img/built/39m0sj94DQ-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;code&gt;ts-node&lt;/code&gt; 讓你在開發時直接執行 &lt;code&gt;.ts&lt;/code&gt; 檔，適合快速測試與腳本；正式部署仍依專案建置流程：&lt;/p&gt;&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; --save-dev ts-node typescript
npx ts-node src/hello.ts&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;TypeScript-Playground&quot;&gt;TypeScript Playground&lt;/h3&gt;&lt;p&gt;不想裝任何東西？&lt;a href=&quot;https://www.typescriptlang.org/play&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;TypeScript Playground&lt;/a&gt; 是線上沙盒，可貼程式碼、看型別錯誤與編譯結果。先在 Playground 把概念煮熟，再搬回專案，通常比直接在正式環境亂加鹽安全。&lt;/p&gt;&lt;h3 id=&quot;Deno&quot;&gt;Deno&lt;/h3&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/3AYMBX_Ib5-240.webp 240w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/3AYMBX_Ib5-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;240&quot; height=&quot;92&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://docs.deno.com/runtime/getting_started/installation/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Deno&lt;/a&gt; 內建 TypeScript 支援，不需先跑 &lt;code&gt;tsc&lt;/code&gt;：&lt;/p&gt;&lt;pre class=&quot;language-typescript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// hello.ts&lt;/span&gt;
&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Hello from Deno!&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;deno run hello.ts&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Deno 是獨立執行環境，請依官方文件安裝，不要用 &lt;code&gt;npm install -g&lt;/code&gt; 取代。&lt;/p&gt;&lt;h3 id=&quot;Bun&quot;&gt;Bun&lt;/h3&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/0rvCce6ac4-240.webp 240w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/0rvCce6ac4-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;240&quot; height=&quot;92&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://bun.sh/docs/installation&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Bun&lt;/a&gt; 同樣能直接執行 &lt;code&gt;.ts&lt;/code&gt;：&lt;/p&gt;&lt;pre class=&quot;language-typescript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// hello.ts&lt;/span&gt;
&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Hello from Bun!&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;bun run hello.ts&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Bun 也是獨立執行環境，不是用 &lt;code&gt;pnpm add bun -g&lt;/code&gt; 取得的 npm 套件。&lt;/p&gt;&lt;h2 id=&quot;常見-FAQ&quot;&gt;常見 FAQ&lt;/h2&gt;&lt;h3 id=&quot;TypeScript-跟-JavaScript-有什麼差別?&quot;&gt;TypeScript 跟 JavaScript 有什麼差別？&lt;/h3&gt;&lt;p&gt;TypeScript 在 JavaScript 語法上加入型別系統；合法 JS 通常也是合法 TS。差別在開發階段多了型別檢查，執行時仍是 JavaScript。&lt;/p&gt;&lt;h3 id=&quot;需要全域安裝-tsc-嗎?&quot;&gt;需要全域安裝 &lt;code&gt;tsc&lt;/code&gt; 嗎？&lt;/h3&gt;&lt;p&gt;不需要。在專案內 &lt;code&gt;npm install --save-dev typescript&lt;/code&gt;，用 &lt;code&gt;npx tsc&lt;/code&gt; 即可。全域安裝容易造成版本不一致，團隊協作時尤其麻煩。&lt;/p&gt;&lt;h3 id=&quot;tsconfig.json-的-strict-要開嗎?&quot;&gt;&lt;code&gt;tsconfig.json&lt;/code&gt; 的 &lt;code&gt;strict&lt;/code&gt; 要開嗎？&lt;/h3&gt;&lt;p&gt;入門建議開 &lt;code&gt;strict: true&lt;/code&gt;。一開始型別錯誤多一點，但長期能避免更多隱性 bug。若遷移舊 JS 專案，可暫時關閉部分選項，再逐步收緊。&lt;/p&gt;&lt;h3 id=&quot;用-Homebrew-可以裝-TypeScript-嗎?&quot;&gt;用 Homebrew 可以裝 TypeScript 嗎？&lt;/h3&gt;&lt;p&gt;Homebrew 適合裝 &lt;strong&gt;Node.js&lt;/strong&gt;（&lt;code&gt;brew install node&lt;/code&gt;），TypeScript 則建議用 npm／pnpm 裝在專案裡。這樣每個專案能鎖定自己的 &lt;code&gt;typescript&lt;/code&gt; 版本，CI 與本機行為也一致。&lt;/p&gt;&lt;h3 id=&quot;Deno-或-Bun-還需要-tsc-嗎?&quot;&gt;Deno 或 Bun 還需要 &lt;code&gt;tsc&lt;/code&gt; 嗎？&lt;/h3&gt;&lt;p&gt;Deno 與 Bun 能直接執行 &lt;code&gt;.ts&lt;/code&gt;，開發腳本時很方便。但若你要產出給 Node.js 或瀏覽器用的 JS、或需要嚴格控制輸出格式，仍建議用 &lt;code&gt;tsc&lt;/code&gt;（或 esbuild、swc 等建置工具）編譯。&lt;/p&gt;&lt;h2 id=&quot;接下來可以學什麼?&quot;&gt;接下來可以學什麼？&lt;/h2&gt;&lt;p&gt;你已完成 TypeScript 入門的基本流程：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;安裝 Node.js 與專案內的 TypeScript&lt;/li&gt;&lt;li&gt;用 &lt;code&gt;tsconfig.json&lt;/code&gt; 設定編譯行為&lt;/li&gt;&lt;li&gt;用 &lt;code&gt;tsc&lt;/code&gt; 檢查並輸出 JavaScript&lt;/li&gt;&lt;li&gt;視情境選擇 Node.js、ts-node、Deno 或 Bun&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;下一步可學基本型別、函式型別、&lt;code&gt;interface&lt;/code&gt;、泛型，以及在既有 JS 專案中逐步加入 TypeScript。先從能讓程式更好理解的型別開始，不必一口氣把整本手冊吞下去——那樣連編譯器都會替你噎到。&lt;/p&gt;&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;TypeScript 官方網站&lt;/a&gt;：語言介紹與最新文件&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/intro.html&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;TypeScript Handbook&lt;/a&gt;：型別系統與語言功能教學&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/tsconfig/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;TypeScript &lt;code&gt;tsconfig.json&lt;/code&gt; 參考&lt;/a&gt;：編譯器選項查詢&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/download&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Node.js 官方下載&lt;/a&gt;：Node.js 安裝方式&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://docs.deno.com/runtime/getting_started/installation/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Deno 安裝文件&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://bun.sh/docs/installation&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Bun 安裝文件&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>TOC（Table of Contents）是什麼？文章目錄做法＋SEO 實務（WordPress／11ty）</title>
    <link href="https://kamadiam.com/table-of-contents/" />
    <updated>2026-08-29T00:00:00Z</updated>
    <id>https://kamadiam.com/table-of-contents/</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;TOC（Table of Contents，文章目錄）&lt;/strong&gt; 是把章節標題變成頁內連結的導覽區塊，讓讀者先看地圖、再跳到需要的段落。長文沒有目錄，讀者就得一路往下捲，像在網頁裡玩「找不同」——不同的是重點到底藏在哪裡。&lt;/p&gt;&lt;p&gt;這篇讀完，你會知道 TOC 對閱讀體驗與 SEO 能幫多少、如何用原生 HTML 做出穩定錨點，以及靜態網站、JavaScript 和 WordPress 各自適合什麼做法。&lt;/p&gt;&lt;h2 id=&quot;快速參考&quot;&gt;快速參考&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;項目&lt;/th&gt;&lt;th&gt;說明&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TOC 是什麼&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;章節標題的頁內導覽清單，通常連到 &lt;code&gt;#錨點&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;對 SEO 有幫助嗎&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;沒有保證加分；清楚的標題結構 + 可爬取的 &lt;code&gt;&amp;lt;a href&amp;gt;&lt;/code&gt; 才是重點&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;靜態站（11ty）&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;建置時產生 HTML，本站用 &lt;code&gt;[[toc]]&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;動態站&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;JS 掃描 H2/H3，或 WordPress TOC 外掛&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;必備條件&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;每個目標標題有唯一 &lt;code&gt;id&lt;/code&gt;，TOC 的 &lt;code&gt;href&lt;/code&gt; 與之對應&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/table-of-contents/#%E5%BF%AB%E9%80%9F%E5%8F%83%E8%80%83&quot;&gt;快速參考&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/table-of-contents/#TOC-%E5%B0%8D%E8%AE%80%E8%80%85%E8%88%87-SEO-%E5%90%84%E5%B9%AB%E4%BB%80%E9%BA%BC?&quot;&gt;TOC 對讀者與 SEO 各幫什麼？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/table-of-contents/#%E5%85%88%E6%8A%8A%E6%A8%99%E9%A1%8C%E5%92%8C%E9%8C%A8%E9%BB%9E%E5%81%9A%E5%A5%BD&quot;&gt;先把標題和錨點做好&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/table-of-contents/#%E4%B8%89%E7%A8%AE-TOC-%E5%AF%A6%E4%BD%9C%E6%96%B9%E5%BC%8F&quot;&gt;三種 TOC 實作方式&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/table-of-contents/#%E7%99%BC%E5%B8%83%E5%89%8D%E6%AA%A2%E6%9F%A5%E6%B8%85%E5%96%AE&quot;&gt;發布前檢查清單&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/table-of-contents/#%E5%B8%B8%E8%A6%8B%E5%95%8F%E9%A1%8C&quot;&gt;常見問題&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/table-of-contents/#%E7%B5%90%E8%AA%9E&quot;&gt;結語&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/table-of-contents/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;TOC-對讀者與-SEO-各幫什麼?&quot;&gt;TOC 對讀者與 SEO 各幫什麼？&lt;/h2&gt;&lt;h3 id=&quot;讀者體驗主要價值&quot;&gt;讀者體驗（主要價值）&lt;/h3&gt;&lt;p&gt;一份好的 TOC 至少有三個用途：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;讓讀者快速掃過文章範圍，判斷內容是否值得讀&lt;/li&gt;&lt;li&gt;讓讀者直接跳到需要的章節，少滑幾個螢幕&lt;/li&gt;&lt;li&gt;讓讀者複製 &lt;code&gt;網址#錨點&lt;/code&gt;，把特定段落分享給別人&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;SEO務實版&quot;&gt;SEO：務實版&lt;/h3&gt;&lt;p&gt;Google &lt;strong&gt;沒有保證&lt;/strong&gt;「加入 TOC 就會排名更高」。比較可靠的做法：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;用一個 H1，再用 H2、H3 分出章節&lt;/li&gt;&lt;li&gt;使用真正的 &lt;code&gt;&amp;lt;a href=&amp;quot;#section-id&amp;quot;&amp;gt;&lt;/code&gt;，而不是只有 JavaScript 點擊&lt;/li&gt;&lt;li&gt;連結文字描述目標內容，不要全部叫「點這裡」&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Google 文件指出，通常需要有 &lt;code&gt;href&lt;/code&gt; 的 &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; 元素，搜尋系統才容易擷取連結。搜尋結果是否顯示頁內跳轉連結，仍由系統自動判斷，不能手動保證。&lt;/p&gt;&lt;p&gt;另外，頁內跳轉（jump link）和 sitelinks 不是同一件事。Google 已於 2024 年 11 月 21 日起移除搜尋結果中的 sitelinks search box，但這不等於一般 sitelinks 或頁內錨點消失。&lt;/p&gt;&lt;h2 id=&quot;先把標題和錨點做好&quot;&gt;先把標題和錨點做好&lt;/h2&gt;&lt;p&gt;TOC 只是導航，不會替混亂的內容結構打掃房間。實作前先確認：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;一篇文章有一個主要 H1&lt;/li&gt;&lt;li&gt;大章節用 H2，小節用 H3，層級不要從 H2 突然跳到 H4&lt;/li&gt;&lt;li&gt;每個目標標題都有唯一且穩定的 &lt;code&gt;id&lt;/code&gt;&lt;/li&gt;&lt;li&gt;TOC 的 &lt;code&gt;href&lt;/code&gt; 必須和目標標題的 &lt;code&gt;id&lt;/code&gt; 完全相同&lt;/li&gt;&lt;/ol&gt;&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;文章標題&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;nav&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-label&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;文章目錄&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ol&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
			&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#intro&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;簡介&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
			&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#setup&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;開始實作&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ol&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;nav&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;intro&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;簡介&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;這裡是文章簡介。&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;setup&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;開始實作&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
		&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;這裡是實作內容。&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;id&lt;/code&gt; 不能在同一頁重複。若兩個標題都叫「結語」，產生器需處理碰撞，例如輸出 &lt;code&gt;結語&lt;/code&gt; 和 &lt;code&gt;結語-1&lt;/code&gt;。&lt;/p&gt;&lt;h2 id=&quot;三種-TOC-實作方式&quot;&gt;三種 TOC 實作方式&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;方式&lt;/th&gt;&lt;th&gt;適合情境&lt;/th&gt;&lt;th&gt;優點&lt;/th&gt;&lt;th&gt;注意&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;A. 建置時靜態產生&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;11ty、Hugo、Astro&lt;/td&gt;&lt;td&gt;無 JS 依賴、SEO 友善、版面穩定&lt;/td&gt;&lt;td&gt;需在建置流程設定&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;B. JavaScript 動態掃描&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;SPA、需摺疊／高亮目前章節&lt;/td&gt;&lt;td&gt;互動彈性高&lt;/td&gt;&lt;td&gt;不應成為唯一導航來源&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;C. WordPress 外掛／區塊&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;WP 部落格&lt;/td&gt;&lt;td&gt;免寫 code&lt;/td&gt;&lt;td&gt;慎選，避免載入過多腳本&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h3 id=&quot;A.-建置時產生靜態-TOC11ty&quot;&gt;A. 建置時產生靜態 TOC（11ty）&lt;/h3&gt;&lt;p&gt;Markdown 內文放標記：&lt;/p&gt;&lt;pre class=&quot;language-markdown&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;[[toc]]&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;建置工具讀取標題，輸出 HTML 清單與錨點。本站 &lt;code&gt;[[toc]]&lt;/code&gt; 由 &lt;code&gt;markdown-it-table-of-contents&lt;/code&gt; 處理，目前設定&lt;strong&gt;只列出 H2&lt;/strong&gt;。H3 會出現在正文，但不會自動列進目錄——這是建置設定，不是 Markdown 的宇宙定律。&lt;/p&gt;&lt;h3 id=&quot;B.-JavaScript-動態掃描標題&quot;&gt;B. JavaScript 動態掃描標題&lt;/h3&gt;&lt;p&gt;適合需要摺疊目錄、標示目前章節的頁面。建議用 &lt;code&gt;createElement&lt;/code&gt; 而非 &lt;code&gt;innerHTML&lt;/code&gt;，避免把標題文字當 HTML 解析：&lt;/p&gt;&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;nav&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;table-of-contents&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;aria-label&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;文章目錄&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;目錄&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ol&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;toc-list&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ol&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;nav&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tocList &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;#toc-list&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; headings &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;article h2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; usedIds &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

headings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;heading&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; heading&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;section-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;index &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; suffix &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;usedIds&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;heading&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;section-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;index &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;suffix&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		suffix &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	heading&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	usedIds&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; item &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;li&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; link &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;a&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	link&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;href &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	link&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; heading&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;link&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	tocList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;若內容在這段程式執行後才載入，需把建立目錄的時機放到內容完成後。&lt;/p&gt;&lt;h3 id=&quot;C.-WordPress-外掛或區塊&quot;&gt;C. WordPress 外掛或區塊&lt;/h3&gt;&lt;p&gt;選外掛時先看：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;能否排除不想出現的標題（如「參考資料」）&lt;/li&gt;&lt;li&gt;輸出是否為真正的 &lt;code&gt;&amp;lt;a href=&amp;quot;#...&amp;quot;&amp;gt;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;能否處理重複標題並產生唯一 ID&lt;/li&gt;&lt;li&gt;手機版是否容易操作，且不載入不必要的腳本&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;發布前檢查清單&quot;&gt;發布前檢查清單&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;[ ] H1、H2、H3 層級符合內容結構&lt;/li&gt;&lt;li&gt;[ ] 每個 TOC 連結都有 &lt;code&gt;href=&amp;quot;#...&amp;quot;&lt;/code&gt;，目標標題有唯一 &lt;code&gt;id&lt;/code&gt;&lt;/li&gt;&lt;li&gt;[ ] 目錄文字和目標標題一致&lt;/li&gt;&lt;li&gt;[ ] 靜態站優先建置時輸出；JS 只負責增強&lt;/li&gt;&lt;li&gt;[ ] 目錄容器有 &lt;code&gt;nav&lt;/code&gt; 和 &lt;code&gt;aria-label&lt;/code&gt;&lt;/li&gt;&lt;li&gt;[ ] 手機版容易收合或掃讀&lt;/li&gt;&lt;li&gt;[ ] 已實際點過每個連結，也測過重新整理後的 &lt;code&gt;#錨點&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;常見問題&quot;&gt;常見問題&lt;/h2&gt;&lt;h3 id=&quot;TOC-一定要放在文章最前面嗎?&quot;&gt;TOC 一定要放在文章最前面嗎？&lt;/h3&gt;&lt;p&gt;長文通常放在引言後最方便掃描；桌面版也可固定在側欄。重點是目錄在 HTML 中真實存在，且連結能直接跳到內容。&lt;/p&gt;&lt;h3 id=&quot;中文標題的-id-怎麼產生?&quot;&gt;中文標題的 &lt;code&gt;id&lt;/code&gt; 怎麼產生？&lt;/h3&gt;&lt;p&gt;可用中文 ID、拼音或其他穩定 slug。重點是規則穩定、結果不重複，且 TOC 與標題共用同一套規則。本站允許中文 slug，TOC 與標題 ID 共用自訂 slugify。&lt;/p&gt;&lt;h3 id=&quot;要不要把-H3-也放進目錄?&quot;&gt;要不要把 H3 也放進目錄？&lt;/h3&gt;&lt;p&gt;看文章長度。小節很多時，H3 會讓目錄變成另一篇文章；小節較少時，列出 H3 能幫助定位。本站目前只輸出 H2；若要 H3 目錄，需調整建置設定。&lt;/p&gt;&lt;h3 id=&quot;TOC-會不會和外掛衝突?&quot;&gt;TOC 會不會和外掛衝突？&lt;/h3&gt;&lt;p&gt;可能。最常見是兩個工具同時替標題產生 ID，導致連結失效。建議由單一工具負責 ID，建置後檢查 HTML 是否有重複 ID。&lt;/p&gt;&lt;h2 id=&quot;結語&quot;&gt;結語&lt;/h2&gt;&lt;p&gt;TOC 的核心價值：讓讀者更快找到重點，也讓頁面結構更容易被理解。靜態站優先選建置時產生的原生 HTML；需要高亮、摺疊時再讓 JavaScript 上場；WordPress 則慎選外掛。&lt;/p&gt;&lt;p&gt;延伸閱讀：&lt;a href=&quot;https://kamadiam.com/11ty-generator/&quot;&gt;11ty 入門&lt;/a&gt;、&lt;a href=&quot;https://kamadiam.com/pagespeed-core-web-vitals/&quot;&gt;PageSpeed 與 Core Web Vitals&lt;/a&gt;。&lt;/p&gt;&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://developers.google.com/search/docs/fundamentals/seo-starter-guide&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Google Search Central：SEO Starter Guide&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developers.google.com/search/docs/crawling-indexing/links-crawlable&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Google Search Central：Make your links crawlable&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developers.google.com/search/blog/2024/10/sitelinks-search-box&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Google Search Central：Farewell, Sitelinks Search Box&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;MDN：HTML &lt;code&gt;id&lt;/code&gt; global attribute&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/languages/markdown/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;11ty 文件：Markdown&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Tab Manager Plus 教學：Chrome 分頁管理終極指南</title>
    <link href="https://kamadiam.com/tab-management/" />
    <updated>2026-08-29T00:00:00Z</updated>
    <id>https://kamadiam.com/tab-management/</id>
    <content type="html">&lt;p&gt;你是不是也有過這種經驗：只是想找一個分頁，卻得在分頁列裡滑到天荒地老，最後連自己要找什麼都忘了？分頁開太多時，瀏覽器的工作列看起來就像咖啡店打烊前的桌面——每一杯都像重要的，但沒人知道哪一杯是你的。&lt;/p&gt;&lt;p&gt;這篇會介紹兩款 Chrome 分頁管理擴充功能：Tab Manager Plus 與 Tab Manager Auto。讀完後，你會知道它們各自適合什麼情境、能處理哪些工作，以及如何選擇；不必再用「關掉全部分頁，靠記憶重新開始」這種有點悲壯的整理法。&lt;/p&gt;&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/tab-management/#%E5%85%88%E8%AA%8D%E8%AD%98-Chrome-%E7%9A%84%E5%88%86%E9%A0%81%E6%95%B4%E7%90%86%E6%96%B9%E5%BC%8F&quot;&gt;先認識 Chrome 的分頁整理方式&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/tab-management/#Tab-Manager-Plus-for-Chrome%E5%BF%AB%E9%80%9F%E6%89%BE%E5%9B%9E%E5%88%86%E9%A0%81&quot;&gt;Tab Manager Plus for Chrome：快速找回分頁&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/tab-management/#Tab-Manager-Auto%E8%AE%93%E5%88%86%E9%A0%81%E6%8C%89%E7%B6%B2%E5%9F%9F%E8%87%AA%E5%8B%95%E5%88%86%E7%B5%84&quot;&gt;Tab Manager Auto：讓分頁按網域自動分組&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/tab-management/#Tab-Manager-Plus-%E8%88%87-Tab-Manager-Auto-%E6%80%8E%E9%BA%BC%E9%81%B8?&quot;&gt;Tab Manager Plus 與 Tab Manager Auto 怎麼選？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/tab-management/#%E4%BD%BF%E7%94%A8%E5%89%8D%E7%9A%84%E5%85%A9%E5%80%8B%E6%8F%90%E9%86%92&quot;&gt;使用前的兩個提醒&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/tab-management/#%E7%B5%90%E8%AA%9E&quot;&gt;結語&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/tab-management/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;先認識-Chrome-的分頁整理方式&quot;&gt;先認識 Chrome 的分頁整理方式&lt;/h2&gt;&lt;p&gt;在開始比較擴充功能前，先釐清問題會比較好。Chrome 本身已經支援分頁群組，可以替群組命名、選顏色、收合分頁，也能把分頁拖進群組。若你只需要偶爾整理幾個主題，內建功能可能已經夠用。&lt;/p&gt;&lt;p&gt;但當你同時開著工作、研究、購物和一堆「等等再看」的分頁時，手動拖曳就會變成另一種工作。這時，擴充功能的價值在於幫你快速找到分頁，或按照規則自動整理。&lt;/p&gt;&lt;h2 id=&quot;Tab-Manager-Plus-for-Chrome快速找回分頁&quot;&gt;Tab Manager Plus for Chrome：快速找回分頁&lt;/h2&gt;&lt;h3 id=&quot;它適合什麼情境?&quot;&gt;它適合什麼情境？&lt;/h3&gt;&lt;p&gt;&lt;a href=&quot;https://chrome.google.com/webstore/detail/tab-manager-plus-for-chro/cnkdjjdmfiffagllbiiilooaoofcoeff&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/VRwjtt4lH1-240.webp 240w, https://kamadiam.com/img/built/VRwjtt4lH1-320.webp 320w, https://kamadiam.com/img/built/VRwjtt4lH1-480.webp 480w, https://kamadiam.com/img/built/VRwjtt4lH1-640.webp 640w, https://kamadiam.com/img/built/VRwjtt4lH1-672.webp 672w, https://kamadiam.com/img/built/VRwjtt4lH1-800.webp 800w, https://kamadiam.com/img/built/VRwjtt4lH1-1076.webp 1076w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/VRwjtt4lH1-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1076&quot; height=&quot;314&quot; srcset=&quot;https://kamadiam.com/img/built/VRwjtt4lH1-240.png 240w, https://kamadiam.com/img/built/VRwjtt4lH1-320.png 320w, https://kamadiam.com/img/built/VRwjtt4lH1-480.png 480w, https://kamadiam.com/img/built/VRwjtt4lH1-640.png 640w, https://kamadiam.com/img/built/VRwjtt4lH1-672.png 672w, https://kamadiam.com/img/built/VRwjtt4lH1-800.png 800w, https://kamadiam.com/img/built/VRwjtt4lH1-1076.png 1076w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Tab Manager Plus 的核心工作很直接：把目前開啟的分頁與視窗集中列出，讓你用標題或網址搜尋，而不是一直在分頁列裡左右滑。Chrome Web Store 的說明也把「快速尋找分頁、查看所有視窗、找出重複分頁、限制每個視窗的分頁數」列為主要功能。&lt;/p&gt;&lt;p&gt;換句話說，它比較像一個「分頁搜尋器」，而不是替你決定所有分頁要怎麼生活。這種工具很適合習慣自己分類、但不想自己找分頁的人。&lt;/p&gt;&lt;h3 id=&quot;主要功能&quot;&gt;主要功能&lt;/h3&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/M1gOKChu_Z-240.webp 240w, https://kamadiam.com/img/built/M1gOKChu_Z-320.webp 320w, https://kamadiam.com/img/built/M1gOKChu_Z-480.webp 480w, https://kamadiam.com/img/built/M1gOKChu_Z-640.webp 640w, https://kamadiam.com/img/built/M1gOKChu_Z-672.webp 672w, https://kamadiam.com/img/built/M1gOKChu_Z-800.webp 800w, https://kamadiam.com/img/built/M1gOKChu_Z-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/M1gOKChu_Z-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;902&quot; srcset=&quot;https://kamadiam.com/img/built/M1gOKChu_Z-240.png 240w, https://kamadiam.com/img/built/M1gOKChu_Z-320.png 320w, https://kamadiam.com/img/built/M1gOKChu_Z-480.png 480w, https://kamadiam.com/img/built/M1gOKChu_Z-640.png 640w, https://kamadiam.com/img/built/M1gOKChu_Z-672.png 672w, https://kamadiam.com/img/built/M1gOKChu_Z-800.png 800w, https://kamadiam.com/img/built/M1gOKChu_Z-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;集中查看&lt;/strong&gt;：一次查看目前視窗中的分頁與視窗，少一點盲目搜尋。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;搜尋標題與網址&lt;/strong&gt;：開啟管理介面後直接輸入關鍵字，縮小結果範圍。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;標記重複分頁&lt;/strong&gt;：找出重複頁面後，再決定要保留、移動或關閉哪些分頁。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;批次管理&lt;/strong&gt;：依商店說明，可選取多個分頁，進行移動、建立或刪除等操作。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;限制分頁數量&lt;/strong&gt;：可以設定每個視窗的分頁上限；達到限制後，擴充功能會依其設定處理後續分頁。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;隱身模式支援&lt;/strong&gt;：這不是安裝後就自動開啟的功能。需要到 Chrome 的擴充功能管理頁，針對該擴充功能開啟「允許在無痕模式中使用」。&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;如果你的痛點是「我明明開過，但它現在在哪裡」，Tab Manager Plus 通常比自動分組更對症。它不會替你安排人生，只負責把分頁叫到你面前——這已經比很多會議主持人可靠了。&lt;/p&gt;&lt;h2 id=&quot;Tab-Manager-Auto讓分頁按網域自動分組&quot;&gt;Tab Manager Auto：讓分頁按網域自動分組&lt;/h2&gt;&lt;h3 id=&quot;它的整理方式&quot;&gt;它的整理方式&lt;/h3&gt;&lt;p&gt;Tab Manager Auto 的方向不同。根據 Chrome Web Store 的功能說明，它會依分頁的來源網域自動分組，也能把最近使用的分頁排到該群組較前面的位置，並允許使用者自訂分組。&lt;/p&gt;&lt;p&gt;想像你開了 GitHub、文件網站和幾個測試頁面。你不必每次都手動拖曳，工具會嘗試依照網域把相關分頁集合起來。分頁終於學會排隊了，只是它不會幫你買咖啡。&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://chrome.google.com/webstore/detail/tab-manager-auto/mplpoddifhoaicmpbjgpfnbljcabibak&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/kZbBsFNSgZ-240.webp 240w, https://kamadiam.com/img/built/kZbBsFNSgZ-320.webp 320w, https://kamadiam.com/img/built/kZbBsFNSgZ-480.webp 480w, https://kamadiam.com/img/built/kZbBsFNSgZ-640.webp 640w, https://kamadiam.com/img/built/kZbBsFNSgZ-672.webp 672w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/kZbBsFNSgZ-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;672&quot; height=&quot;185&quot; srcset=&quot;https://kamadiam.com/img/built/kZbBsFNSgZ-240.png 240w, https://kamadiam.com/img/built/kZbBsFNSgZ-320.png 320w, https://kamadiam.com/img/built/kZbBsFNSgZ-480.png 480w, https://kamadiam.com/img/built/kZbBsFNSgZ-640.png 640w, https://kamadiam.com/img/built/kZbBsFNSgZ-672.png 672w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/a&gt;&lt;/p&gt;&lt;h3 id=&quot;主要功能-2&quot;&gt;主要功能&lt;/h3&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/mf3pvxVHAt-240.webp 240w, https://kamadiam.com/img/built/mf3pvxVHAt-320.webp 320w, https://kamadiam.com/img/built/mf3pvxVHAt-480.webp 480w, https://kamadiam.com/img/built/mf3pvxVHAt-640.webp 640w, https://kamadiam.com/img/built/mf3pvxVHAt-672.webp 672w, https://kamadiam.com/img/built/mf3pvxVHAt-800.webp 800w, https://kamadiam.com/img/built/mf3pvxVHAt-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/mf3pvxVHAt-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;42&quot; srcset=&quot;https://kamadiam.com/img/built/mf3pvxVHAt-240.png 240w, https://kamadiam.com/img/built/mf3pvxVHAt-320.png 320w, https://kamadiam.com/img/built/mf3pvxVHAt-480.png 480w, https://kamadiam.com/img/built/mf3pvxVHAt-640.png 640w, https://kamadiam.com/img/built/mf3pvxVHAt-672.png 672w, https://kamadiam.com/img/built/mf3pvxVHAt-800.png 800w, https://kamadiam.com/img/built/mf3pvxVHAt-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;依網域分組&lt;/strong&gt;：相同來源網域的分頁會被安排到同一組。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;依最近使用狀態排序&lt;/strong&gt;：商店說明指出，最後使用的分頁會被移到所屬群組較前的位置。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;自訂群組&lt;/strong&gt;：除了自動整理，也可以建立自己的分頁群組。&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;這款工具適合「我不想每天整理，但希望分頁至少不要散落各處」的人。不過，自動化不代表永遠符合你的工作習慣；如果不同專案使用同一個網域，最後仍可能需要手動調整。&lt;/p&gt;&lt;h2 id=&quot;Tab-Manager-Plus-與-Tab-Manager-Auto-怎麼選?&quot;&gt;Tab Manager Plus 與 Tab Manager Auto 怎麼選？&lt;/h2&gt;&lt;p&gt;兩款工具不是誰一定比較強，而是解決的問題不同。先問自己：「我最常浪費時間在找分頁，還是整理分頁？」&lt;/p&gt;&lt;h3 id=&quot;需要搜尋與控制選-Tab-Manager-Plus&quot;&gt;需要搜尋與控制：選 Tab Manager Plus&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;分頁很多，常常找不到某一頁。&lt;/li&gt;&lt;li&gt;需要跨多個視窗搜尋與移動分頁。&lt;/li&gt;&lt;li&gt;想自己決定哪些分頁要保留或關閉。&lt;/li&gt;&lt;li&gt;偶爾才整理一次，不希望工具一直改變分頁配置。&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;需要自動分組選-Tab-Manager-Auto&quot;&gt;需要自動分組：選 Tab Manager Auto&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;你常同時開啟同一網站的多個分頁。&lt;/li&gt;&lt;li&gt;希望分頁依網域自動集合。&lt;/li&gt;&lt;li&gt;可以接受偶爾檢查自動分組結果。&lt;/li&gt;&lt;li&gt;想把手動拖曳的時間交給工具處理。&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;兩者一起用可以嗎?&quot;&gt;兩者一起用可以嗎？&lt;/h3&gt;&lt;p&gt;技術上可以同時安裝，但不代表一定要同時啟用所有自動功能。Tab Manager Auto 負責按規則整理，Tab Manager Plus 負責搜尋與批次管理；如果兩者同時修改分頁位置，結果可能和你的預期不同。&lt;/p&gt;&lt;p&gt;建議先安裝一款，使用幾天後再決定是否需要另一款。擴充功能越多不一定越有效率，瀏覽器不是自助餐盤，拿太多最後只會端不穩。&lt;/p&gt;&lt;h2 id=&quot;使用前的兩個提醒&quot;&gt;使用前的兩個提醒&lt;/h2&gt;&lt;p&gt;第一，安裝擴充功能前，請查看它要求的權限與開發者資訊，只安裝你信任的工具。Chrome 官方也提醒，擴充功能可能需要讀取或變更你造訪網站上的資料，因此權限不是可以一路按「同意」帶過的小字。&lt;/p&gt;&lt;p&gt;第二，若要在無痕模式使用擴充功能，請開啟 &lt;code&gt;chrome://extensions&lt;/code&gt;，找到擴充功能並進入「詳細資料」，再打開「允許在無痕模式中使用」。無痕模式不會讓擴充功能自動獲得這項權限；而且無痕視窗的工作階段資料也有不同的保存規則，別把它當成普通視窗的隱形斗篷。&lt;/p&gt;&lt;h2 id=&quot;結語&quot;&gt;結語&lt;/h2&gt;&lt;p&gt;如果你最常說的是「那個分頁到底在哪裡」，先試 Tab Manager Plus；如果你更想要「分頁自己按網域排好」，可以試 Tab Manager Auto。也可以先使用 Chrome 內建的分頁群組，確認自己的整理習慣後，再決定是否需要擴充功能。&lt;/p&gt;&lt;p&gt;分頁管理的目標不是把分頁列整理得像樣品屋，而是讓你下一次找資料時，真的找得到。整理完記得喝口咖啡——分頁可以自動分組，咖啡目前還不會。&lt;/p&gt;&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://chromewebstore.google.com/detail/tab-manager-plus-for-chro/cnkdjjdmfiffagllbiiilooofcoeff&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Tab Manager Plus for Chrome｜Chrome Web Store&lt;/a&gt;：查閱擴充功能列出的搜尋分頁、重複分頁、視窗管理與分頁限制等功能。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://chromewebstore.google.com/detail/tab-manager-auto/mplpoddifhoaicmpbjgpfnbljcabibak&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Tab Manager Auto｜Chrome Web Store&lt;/a&gt;：查閱依來源網域自動分組、最近使用分頁排序與自訂分組的功能說明。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://support.google.com/chrome/answer/2664769?hl=zh-Hant&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;安裝及管理擴充功能｜Google Chrome 說明&lt;/a&gt;：查閱安裝擴充功能、檢查權限，以及開啟無痕模式使用權限的步驟。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://support.google.com/chrome/answer/2391819?hl=zh-Hant&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;管理 Chrome 中的分頁｜Google Chrome 說明&lt;/a&gt;：查閱 Chrome 內建分頁群組、命名、收合與同步等功能。&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Statamic 教學：Flat-file CMS 入門 vs WordPress／11ty</title>
    <link href="https://kamadiam.com/statamic-getting-started/" />
    <updated>2026-08-29T00:00:00Z</updated>
    <id>https://kamadiam.com/statamic-getting-started/</id>
    <content type="html">&lt;p&gt;WordPress 功能很多，這是優點，也是有時讓人打開後台就先想泡咖啡的原因。如果你想要一個能用控制面板管理內容、又能把內容和模板放進 Git 的 CMS，Statamic 值得認真看一眼。它把 CMS 的方便，和檔案型工作流程放在同一張桌上——咖啡則放旁邊，避免灑到 YAML。&lt;/p&gt;&lt;p&gt;這篇會帶你認識 Statamic 的 flat-file 模式、用 Laravel Herd 建立本機環境，接著做出首頁、文章集合、文章列表與可重複使用的模板片段。讀完後，你也會知道它和 WordPress、11ty 的定位差在哪裡，以及什麼情況適合選它。&lt;/p&gt;&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/statamic-getting-started/#Statamic-%E6%98%AF%E4%BB%80%E9%BA%BC?&quot;&gt;Statamic 是什麼？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/statamic-getting-started/#%E5%A4%96%E6%8E%9B%E8%88%87-Starter-Kits&quot;&gt;外掛與 Starter Kits&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/statamic-getting-started/#%E5%85%88%E6%BA%96%E5%82%99%E6%9C%AC%E6%A9%9F%E9%96%8B%E7%99%BC%E7%92%B0%E5%A2%83&quot;&gt;先準備本機開發環境&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/statamic-getting-started/#%E8%AA%8D%E8%AD%98%E9%A6%96%E9%A0%81%E8%88%87-Antlers-%E6%A8%A1%E6%9D%BF&quot;&gt;認識首頁與 Antlers 模板&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/statamic-getting-started/#%E5%BB%BA%E7%AB%8B%E9%83%A8%E8%90%BD%E6%A0%BC%E7%9A%84%E5%85%A7%E5%AE%B9%E9%9B%86%E5%90%88&quot;&gt;建立部落格的內容集合&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/statamic-getting-started/#%E9%A1%AF%E7%A4%BA%E6%96%87%E7%AB%A0%E5%88%97%E8%A1%A8&quot;&gt;顯示文章列表&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/statamic-getting-started/#%E6%8A%8A%E9%87%8D%E8%A4%87%E5%85%A7%E5%AE%B9%E6%8A%BD%E6%88%90-Partial&quot;&gt;把重複內容抽成 Partial&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/statamic-getting-started/#%E5%8A%A0%E4%B8%8A%E5%B0%8E%E8%A6%BD%E5%88%97&quot;&gt;加上導覽列&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/statamic-getting-started/#%E7%94%A8-Blueprint-%E5%A2%9E%E5%8A%A0%E7%B2%BE%E9%81%B8%E5%9C%96%E7%89%87&quot;&gt;用 Blueprint 增加精選圖片&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/statamic-getting-started/#StatamicWordPress-%E8%88%87-11ty-%E6%80%8E%E9%BA%BC%E9%81%B8?&quot;&gt;Statamic、WordPress 與 11ty 怎麼選？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/statamic-getting-started/#%E9%81%A9%E5%90%88%E8%AA%B0%E4%BD%BF%E7%94%A8?&quot;&gt;適合誰使用？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/statamic-getting-started/#%E7%B5%90%E8%AA%9E&quot;&gt;結語&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/statamic-getting-started/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;Statamic-是什麼?&quot;&gt;Statamic 是什麼？&lt;/h2&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/aVNw1Fc5b1-240.webp 240w, https://kamadiam.com/img/built/aVNw1Fc5b1-320.webp 320w, https://kamadiam.com/img/built/aVNw1Fc5b1-480.webp 480w, https://kamadiam.com/img/built/aVNw1Fc5b1-640.webp 640w, https://kamadiam.com/img/built/aVNw1Fc5b1-672.webp 672w, https://kamadiam.com/img/built/aVNw1Fc5b1-800.webp 800w, https://kamadiam.com/img/built/aVNw1Fc5b1-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/aVNw1Fc5b1-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;638&quot; srcset=&quot;https://kamadiam.com/img/built/aVNw1Fc5b1-240.png 240w, https://kamadiam.com/img/built/aVNw1Fc5b1-320.png 320w, https://kamadiam.com/img/built/aVNw1Fc5b1-480.png 480w, https://kamadiam.com/img/built/aVNw1Fc5b1-640.png 640w, https://kamadiam.com/img/built/aVNw1Fc5b1-672.png 672w, https://kamadiam.com/img/built/aVNw1Fc5b1-800.png 800w, https://kamadiam.com/img/built/aVNw1Fc5b1-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;Statamic 是建立在 Laravel 上的內容管理系統。它預設使用 flat-file 模式：內容、設定與模板可以用 YAML、Markdown、Antlers 模板等檔案管理，而不是一開始就要求你準備資料庫。&lt;/p&gt;&lt;p&gt;「檔案型」不代表它只有編輯器。Statamic 仍然提供控制面板、內容集合、欄位藍圖、路由和模板系統；需要時，也能改用資料庫儲存。這種設計的重點，是先讓專案保持簡單，等需求真的長大再決定資料儲存方式。&lt;/p&gt;&lt;p&gt;換句話說，Statamic 不是把 CMS 藏在資料庫裡，而是讓你可以在控制面板和程式碼編輯器之間自由切換。內容可以給編輯者管理，結構和模板則可以交給 Git 追蹤。這比在資料庫裡尋找某段設定，少一點考古，多一點開發。&lt;/p&gt;&lt;h2 id=&quot;外掛與-Starter-Kits&quot;&gt;外掛與 Starter Kits&lt;/h2&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/HfTAUAJ_5D-240.webp 240w, https://kamadiam.com/img/built/HfTAUAJ_5D-320.webp 320w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/HfTAUAJ_5D-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;320&quot; height=&quot;200&quot; srcset=&quot;https://kamadiam.com/img/built/HfTAUAJ_5D-240.png 240w, https://kamadiam.com/img/built/HfTAUAJ_5D-320.png 320w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;Statamic 有外掛與 Marketplace，可以依專案需求增加功能。不過，選外掛前仍然要先確認相容版本、維護狀態和授權方式；「有外掛」不等於「所有外掛都該裝」。外掛裝太多，網站會像咖啡加了十種糖漿：不是不能喝，但已經忘記原本是什麼味道。&lt;/p&gt;&lt;h3 id=&quot;Starter-Kits-是什麼?&quot;&gt;Starter Kits 是什麼？&lt;/h3&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/oZPoadNdix-240.webp 240w, https://kamadiam.com/img/built/oZPoadNdix-320.webp 320w, https://kamadiam.com/img/built/oZPoadNdix-480.webp 480w, https://kamadiam.com/img/built/oZPoadNdix-640.webp 640w, https://kamadiam.com/img/built/oZPoadNdix-672.webp 672w, https://kamadiam.com/img/built/oZPoadNdix-800.webp 800w, https://kamadiam.com/img/built/oZPoadNdix-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/oZPoadNdix-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;776&quot; srcset=&quot;https://kamadiam.com/img/built/oZPoadNdix-240.png 240w, https://kamadiam.com/img/built/oZPoadNdix-320.png 320w, https://kamadiam.com/img/built/oZPoadNdix-480.png 480w, https://kamadiam.com/img/built/oZPoadNdix-640.png 640w, https://kamadiam.com/img/built/oZPoadNdix-672.png 672w, https://kamadiam.com/img/built/oZPoadNdix-800.png 800w, https://kamadiam.com/img/built/oZPoadNdix-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;Starter Kits 是預先準備好的網站起點，通常包含內容結構、模板、樣式和功能。它們比較像「可以繼續修改的專案骨架」，不是 WordPress 那種套上去就結束的主題。每個 Kit 可以有自己的內容模型與設計，因此使用前要先看清楚它包含哪些檔案和功能。&lt;/p&gt;&lt;p&gt;第一次使用時，建議先從空白專案開始。你會比較清楚每一個集合、欄位和模板從哪裡來；熟悉後，再用 Starter Kit 加速重複性高的專案。&lt;/p&gt;&lt;h2 id=&quot;先準備本機開發環境&quot;&gt;先準備本機開發環境&lt;/h2&gt;&lt;p&gt;Statamic 的官方文件把 Laravel Herd 列為 macOS 和 Windows 初學者的推薦路徑。Herd 會協助準備 PHP、Composer 和本機 Web 伺服器，省下手動拼裝開發環境的步驟。&lt;/p&gt;&lt;p&gt;如果你已經有 PHP 和 Composer，也可以直接使用 Statamic CLI。這篇先採 Herd 路線，因為少一點環境設定，就多一點時間看網站真的跑起來。&lt;/p&gt;&lt;h3 id=&quot;使用-Laravel-Herd&quot;&gt;使用 Laravel Herd&lt;/h3&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/fGEJY7Y1pI-240.webp 240w, https://kamadiam.com/img/built/fGEJY7Y1pI-320.webp 320w, https://kamadiam.com/img/built/fGEJY7Y1pI-480.webp 480w, https://kamadiam.com/img/built/fGEJY7Y1pI-640.webp 640w, https://kamadiam.com/img/built/fGEJY7Y1pI-672.webp 672w, https://kamadiam.com/img/built/fGEJY7Y1pI-800.webp 800w, https://kamadiam.com/img/built/fGEJY7Y1pI-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/fGEJY7Y1pI-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;900&quot; srcset=&quot;https://kamadiam.com/img/built/fGEJY7Y1pI-240.png 240w, https://kamadiam.com/img/built/fGEJY7Y1pI-320.png 320w, https://kamadiam.com/img/built/fGEJY7Y1pI-480.png 480w, https://kamadiam.com/img/built/fGEJY7Y1pI-640.png 640w, https://kamadiam.com/img/built/fGEJY7Y1pI-672.png 672w, https://kamadiam.com/img/built/fGEJY7Y1pI-800.png 800w, https://kamadiam.com/img/built/fGEJY7Y1pI-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;安裝 Herd 後，把專案放進 Herd 管理的目錄，再安裝 Statamic CLI：&lt;/p&gt;&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;composer&lt;/span&gt; global require statamic/cli&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;接著建立一個新專案。這個指令會啟動設定精靈，讓你選擇空白網站或 Starter Kit，並建立第一位管理者：&lt;/p&gt;&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; ~/Herd
statamic new try-statamic&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;完成後，Herd 會把專案提供在類似以下的本機網址：&lt;/p&gt;&lt;pre class=&quot;language-text&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;http://try-statamic.test&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;控制面板則位於 &lt;code&gt;/cp&lt;/code&gt;：&lt;/p&gt;&lt;pre class=&quot;language-text&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;http://try-statamic.test/cp&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/diR2LzKEWJ-240.webp 240w, https://kamadiam.com/img/built/diR2LzKEWJ-320.webp 320w, https://kamadiam.com/img/built/diR2LzKEWJ-480.webp 480w, https://kamadiam.com/img/built/diR2LzKEWJ-640.webp 640w, https://kamadiam.com/img/built/diR2LzKEWJ-672.webp 672w, https://kamadiam.com/img/built/diR2LzKEWJ-800.webp 800w, https://kamadiam.com/img/built/diR2LzKEWJ-1198.webp 1198w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/diR2LzKEWJ-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1198&quot; height=&quot;1144&quot; srcset=&quot;https://kamadiam.com/img/built/diR2LzKEWJ-240.png 240w, https://kamadiam.com/img/built/diR2LzKEWJ-320.png 320w, https://kamadiam.com/img/built/diR2LzKEWJ-480.png 480w, https://kamadiam.com/img/built/diR2LzKEWJ-640.png 640w, https://kamadiam.com/img/built/diR2LzKEWJ-672.png 672w, https://kamadiam.com/img/built/diR2LzKEWJ-800.png 800w, https://kamadiam.com/img/built/diR2LzKEWJ-1198.png 1198w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/F1ZClxgADa-240.webp 240w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/F1ZClxgADa-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;240&quot; height=&quot;232&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/_BwPYXL20T-240.webp 240w, https://kamadiam.com/img/built/_BwPYXL20T-320.webp 320w, https://kamadiam.com/img/built/_BwPYXL20T-480.webp 480w, https://kamadiam.com/img/built/_BwPYXL20T-640.webp 640w, https://kamadiam.com/img/built/_BwPYXL20T-672.webp 672w, https://kamadiam.com/img/built/_BwPYXL20T-800.webp 800w, https://kamadiam.com/img/built/_BwPYXL20T-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/_BwPYXL20T-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;630&quot; srcset=&quot;https://kamadiam.com/img/built/_BwPYXL20T-240.png 240w, https://kamadiam.com/img/built/_BwPYXL20T-320.png 320w, https://kamadiam.com/img/built/_BwPYXL20T-480.png 480w, https://kamadiam.com/img/built/_BwPYXL20T-640.png 640w, https://kamadiam.com/img/built/_BwPYXL20T-672.png 672w, https://kamadiam.com/img/built/_BwPYXL20T-800.png 800w, https://kamadiam.com/img/built/_BwPYXL20T-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;看到首頁和登入畫面，就代表基本環境完成。接下來不急著安裝十個套件，我們先做一個最小的內容流程。&lt;/p&gt;&lt;h2 id=&quot;認識首頁與-Antlers-模板&quot;&gt;認識首頁與 Antlers 模板&lt;/h2&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/0wXjIC1ZWi-207.webp 207w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/0wXjIC1ZWi-207.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;207&quot; height=&quot;300&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/iJU_b7yP3E-240.webp 240w, https://kamadiam.com/img/built/iJU_b7yP3E-320.webp 320w, https://kamadiam.com/img/built/iJU_b7yP3E-480.webp 480w, https://kamadiam.com/img/built/iJU_b7yP3E-640.webp 640w, https://kamadiam.com/img/built/iJU_b7yP3E-672.webp 672w, https://kamadiam.com/img/built/iJU_b7yP3E-800.webp 800w, https://kamadiam.com/img/built/iJU_b7yP3E-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/iJU_b7yP3E-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;208&quot; srcset=&quot;https://kamadiam.com/img/built/iJU_b7yP3E-240.png 240w, https://kamadiam.com/img/built/iJU_b7yP3E-320.png 320w, https://kamadiam.com/img/built/iJU_b7yP3E-480.png 480w, https://kamadiam.com/img/built/iJU_b7yP3E-640.png 640w, https://kamadiam.com/img/built/iJU_b7yP3E-672.png 672w, https://kamadiam.com/img/built/iJU_b7yP3E-800.png 800w, https://kamadiam.com/img/built/iJU_b7yP3E-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/GIqrK4m0if-240.webp 240w, https://kamadiam.com/img/built/GIqrK4m0if-320.webp 320w, https://kamadiam.com/img/built/GIqrK4m0if-480.webp 480w, https://kamadiam.com/img/built/GIqrK4m0if-640.webp 640w, https://kamadiam.com/img/built/GIqrK4m0if-672.webp 672w, https://kamadiam.com/img/built/GIqrK4m0if-800.webp 800w, https://kamadiam.com/img/built/GIqrK4m0if-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/GIqrK4m0if-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;590&quot; srcset=&quot;https://kamadiam.com/img/built/GIqrK4m0if-240.png 240w, https://kamadiam.com/img/built/GIqrK4m0if-320.png 320w, https://kamadiam.com/img/built/GIqrK4m0if-480.png 480w, https://kamadiam.com/img/built/GIqrK4m0if-640.png 640w, https://kamadiam.com/img/built/GIqrK4m0if-672.png 672w, https://kamadiam.com/img/built/GIqrK4m0if-800.png 800w, https://kamadiam.com/img/built/GIqrK4m0if-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;Statamic 的預設首頁模板位於 &lt;code&gt;resources/views/home.antlers.html&lt;/code&gt;。副檔名中的 &lt;code&gt;.antlers.html&lt;/code&gt; 很重要：它告訴 Statamic 這是一個要由 Antlers 解析的模板，不是原封不動送出的 HTML。&lt;/p&gt;&lt;p&gt;最小的首頁可以先這樣寫：&lt;/p&gt;&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;歡迎光臨我的 Statamic 實驗站！&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

{{ content }}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;{{ content }}&lt;/code&gt; 會放入目前頁面的內容。模板儲存後重新整理頁面，就能看到結果。Antlers 使用雙大括號，看起來像鬍子；如果模板開始長出真的鬍子，通常是熬夜太久，不是語法功能。&lt;/p&gt;&lt;h3 id=&quot;Layout-負責共同外框&quot;&gt;Layout 負責共同外框&lt;/h3&gt;&lt;p&gt;網站的共同結構通常放在 &lt;code&gt;resources/views/layout.antlers.html&lt;/code&gt;，例如 HTML 外框、導覽列、頁尾和資產引用。頁面模板產生的內容，會插入 &lt;code&gt;{{ template_content }}&lt;/code&gt; 的位置：&lt;/p&gt;&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token doctype&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span class=&quot;token doctype-tag&quot;&gt;doctype&lt;/span&gt; &lt;span class=&quot;token name&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;html&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;lang&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{{ site:short_locale }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;charset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;utf-8&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width, initial-scale=1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{{ title ?? site:name }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    {{ template_content }}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;你可以把 Layout 想成相框：每一頁的內容會變，外框則可以共用。這樣修改頁尾時，不必逐頁複製貼上，少一次複製，也少一次「為什麼只有這頁沒有更新」的偵探劇。&lt;/p&gt;&lt;h2 id=&quot;建立部落格的內容集合&quot;&gt;建立部落格的內容集合&lt;/h2&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/za8-TXmmzh-240.webp 240w, https://kamadiam.com/img/built/za8-TXmmzh-320.webp 320w, https://kamadiam.com/img/built/za8-TXmmzh-480.webp 480w, https://kamadiam.com/img/built/za8-TXmmzh-640.webp 640w, https://kamadiam.com/img/built/za8-TXmmzh-672.webp 672w, https://kamadiam.com/img/built/za8-TXmmzh-800.webp 800w, https://kamadiam.com/img/built/za8-TXmmzh-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/za8-TXmmzh-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;742&quot; srcset=&quot;https://kamadiam.com/img/built/za8-TXmmzh-240.png 240w, https://kamadiam.com/img/built/za8-TXmmzh-320.png 320w, https://kamadiam.com/img/built/za8-TXmmzh-480.png 480w, https://kamadiam.com/img/built/za8-TXmmzh-640.png 640w, https://kamadiam.com/img/built/za8-TXmmzh-672.png 672w, https://kamadiam.com/img/built/za8-TXmmzh-800.png 800w, https://kamadiam.com/img/built/za8-TXmmzh-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;在 Statamic 裡，Collection 是一組有共同結構的內容，例如文章、產品或作品集。建立 &lt;code&gt;blog&lt;/code&gt; 集合後，文章項目會依集合設定儲存；flat-file 模式下，你可以在專案內直接找到並編輯這些 Markdown 檔案。&lt;/p&gt;&lt;p&gt;先規劃一個簡單的部落格：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;title&lt;/code&gt;：文章標題&lt;/li&gt;&lt;li&gt;&lt;code&gt;date&lt;/code&gt;：發布日期&lt;/li&gt;&lt;li&gt;&lt;code&gt;author&lt;/code&gt;：作者&lt;/li&gt;&lt;li&gt;&lt;code&gt;content&lt;/code&gt;：正文&lt;/li&gt;&lt;li&gt;&lt;code&gt;featured_image&lt;/code&gt;：精選圖片&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;欄位不是越多越專業。先從讀者真的需要的資料開始，之後再透過 Blueprint 增加欄位。&lt;/p&gt;&lt;h3 id=&quot;產生文章模板&quot;&gt;產生文章模板&lt;/h3&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/SVg-j9xQi8-240.webp 240w, https://kamadiam.com/img/built/SVg-j9xQi8-320.webp 320w, https://kamadiam.com/img/built/SVg-j9xQi8-480.webp 480w, https://kamadiam.com/img/built/SVg-j9xQi8-640.webp 640w, https://kamadiam.com/img/built/SVg-j9xQi8-672.webp 672w, https://kamadiam.com/img/built/SVg-j9xQi8-800.webp 800w, https://kamadiam.com/img/built/SVg-j9xQi8-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/SVg-j9xQi8-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;336&quot; srcset=&quot;https://kamadiam.com/img/built/SVg-j9xQi8-240.png 240w, https://kamadiam.com/img/built/SVg-j9xQi8-320.png 320w, https://kamadiam.com/img/built/SVg-j9xQi8-480.png 480w, https://kamadiam.com/img/built/SVg-j9xQi8-640.png 640w, https://kamadiam.com/img/built/SVg-j9xQi8-672.png 672w, https://kamadiam.com/img/built/SVg-j9xQi8-800.png 800w, https://kamadiam.com/img/built/SVg-j9xQi8-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/37s9_CL0wI-240.webp 240w, https://kamadiam.com/img/built/37s9_CL0wI-320.webp 320w, https://kamadiam.com/img/built/37s9_CL0wI-480.webp 480w, https://kamadiam.com/img/built/37s9_CL0wI-640.webp 640w, https://kamadiam.com/img/built/37s9_CL0wI-672.webp 672w, https://kamadiam.com/img/built/37s9_CL0wI-800.webp 800w, https://kamadiam.com/img/built/37s9_CL0wI-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/37s9_CL0wI-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;510&quot; srcset=&quot;https://kamadiam.com/img/built/37s9_CL0wI-240.png 240w, https://kamadiam.com/img/built/37s9_CL0wI-320.png 320w, https://kamadiam.com/img/built/37s9_CL0wI-480.png 480w, https://kamadiam.com/img/built/37s9_CL0wI-640.png 640w, https://kamadiam.com/img/built/37s9_CL0wI-672.png 672w, https://kamadiam.com/img/built/37s9_CL0wI-800.png 800w, https://kamadiam.com/img/built/37s9_CL0wI-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;建立集合時，Statamic 可以協助產生基本模板，例如：&lt;/p&gt;&lt;pre class=&quot;language-text&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;resources/views/blog/index.antlers.html
resources/views/blog/show.antlers.html&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;前者用來顯示文章列表，後者用來顯示單篇文章。若你的專案版本或設定產生了不同的檔案名稱，請以實際產生的檔案為準；模板路徑是專案設定的一部分，不要只靠截圖猜路徑。&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/jDPfdpNjZ9-240.webp 240w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/jDPfdpNjZ9-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;240&quot; height=&quot;284&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;h3 id=&quot;設定日期與網址&quot;&gt;設定日期與網址&lt;/h3&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/QYWamz1FE5-240.webp 240w, https://kamadiam.com/img/built/QYWamz1FE5-320.webp 320w, https://kamadiam.com/img/built/QYWamz1FE5-480.webp 480w, https://kamadiam.com/img/built/QYWamz1FE5-640.webp 640w, https://kamadiam.com/img/built/QYWamz1FE5-672.webp 672w, https://kamadiam.com/img/built/QYWamz1FE5-800.webp 800w, https://kamadiam.com/img/built/QYWamz1FE5-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/QYWamz1FE5-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;341&quot; srcset=&quot;https://kamadiam.com/img/built/QYWamz1FE5-240.png 240w, https://kamadiam.com/img/built/QYWamz1FE5-320.png 320w, https://kamadiam.com/img/built/QYWamz1FE5-480.png 480w, https://kamadiam.com/img/built/QYWamz1FE5-640.png 640w, https://kamadiam.com/img/built/QYWamz1FE5-672.png 672w, https://kamadiam.com/img/built/QYWamz1FE5-800.png 800w, https://kamadiam.com/img/built/QYWamz1FE5-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;發布日期不是每個網站都必須顯示的欄位，但部落格通常需要它來排序和呈現文章資訊。網址則由 Collection 的 route 設定決定，建議一開始保持簡單，確定內容模型後再設計更複雜的 URL。&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/cz9y1Px3Zb-240.webp 240w, https://kamadiam.com/img/built/cz9y1Px3Zb-320.webp 320w, https://kamadiam.com/img/built/cz9y1Px3Zb-480.webp 480w, https://kamadiam.com/img/built/cz9y1Px3Zb-640.webp 640w, https://kamadiam.com/img/built/cz9y1Px3Zb-672.webp 672w, https://kamadiam.com/img/built/cz9y1Px3Zb-800.webp 800w, https://kamadiam.com/img/built/cz9y1Px3Zb-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/cz9y1Px3Zb-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;587&quot; srcset=&quot;https://kamadiam.com/img/built/cz9y1Px3Zb-240.png 240w, https://kamadiam.com/img/built/cz9y1Px3Zb-320.png 320w, https://kamadiam.com/img/built/cz9y1Px3Zb-480.png 480w, https://kamadiam.com/img/built/cz9y1Px3Zb-640.png 640w, https://kamadiam.com/img/built/cz9y1Px3Zb-672.png 672w, https://kamadiam.com/img/built/cz9y1Px3Zb-800.png 800w, https://kamadiam.com/img/built/cz9y1Px3Zb-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/2iA12LCQIq-240.webp 240w, https://kamadiam.com/img/built/2iA12LCQIq-320.webp 320w, https://kamadiam.com/img/built/2iA12LCQIq-480.webp 480w, https://kamadiam.com/img/built/2iA12LCQIq-640.webp 640w, https://kamadiam.com/img/built/2iA12LCQIq-672.webp 672w, https://kamadiam.com/img/built/2iA12LCQIq-800.webp 800w, https://kamadiam.com/img/built/2iA12LCQIq-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/2iA12LCQIq-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;204&quot; srcset=&quot;https://kamadiam.com/img/built/2iA12LCQIq-240.png 240w, https://kamadiam.com/img/built/2iA12LCQIq-320.png 320w, https://kamadiam.com/img/built/2iA12LCQIq-480.png 480w, https://kamadiam.com/img/built/2iA12LCQIq-640.png 640w, https://kamadiam.com/img/built/2iA12LCQIq-672.png 672w, https://kamadiam.com/img/built/2iA12LCQIq-800.png 800w, https://kamadiam.com/img/built/2iA12LCQIq-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/gEnHF7yzj8-240.webp 240w, https://kamadiam.com/img/built/gEnHF7yzj8-320.webp 320w, https://kamadiam.com/img/built/gEnHF7yzj8-480.webp 480w, https://kamadiam.com/img/built/gEnHF7yzj8-640.webp 640w, https://kamadiam.com/img/built/gEnHF7yzj8-672.webp 672w, https://kamadiam.com/img/built/gEnHF7yzj8-800.webp 800w, https://kamadiam.com/img/built/gEnHF7yzj8-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/gEnHF7yzj8-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;402&quot; srcset=&quot;https://kamadiam.com/img/built/gEnHF7yzj8-240.png 240w, https://kamadiam.com/img/built/gEnHF7yzj8-320.png 320w, https://kamadiam.com/img/built/gEnHF7yzj8-480.png 480w, https://kamadiam.com/img/built/gEnHF7yzj8-640.png 640w, https://kamadiam.com/img/built/gEnHF7yzj8-672.png 672w, https://kamadiam.com/img/built/gEnHF7yzj8-800.png 800w, https://kamadiam.com/img/built/gEnHF7yzj8-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;h2 id=&quot;顯示文章列表&quot;&gt;顯示文章列表&lt;/h2&gt;&lt;p&gt;建立第一篇文章後，就可以用 Collection Tag 讀取 &lt;code&gt;blog&lt;/code&gt; 集合。下面的例子把最多五篇文章列在首頁：&lt;/p&gt;&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{{ title }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{{ content }}

&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    {{ collection:blog limit=&quot;5&quot; }}
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{{ url }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
                &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{{ title }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
                &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{{ date }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    {{ /collection:blog }}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;collection:blog&lt;/code&gt; 會讀取 &lt;code&gt;blog&lt;/code&gt; 集合，&lt;code&gt;limit=&amp;quot;5&amp;quot;&lt;/code&gt; 則限制輸出數量。這裡的 &lt;code&gt;blog&lt;/code&gt; 是集合 handle，不是隨便取的裝飾文字；handle 打錯時，模板通常不會替你把咖啡端過來。&lt;/p&gt;&lt;h3 id=&quot;部落格索引頁&quot;&gt;部落格索引頁&lt;/h3&gt;&lt;p&gt;在 Pages 集合建立一個部落格頁面，將它設為文章列表使用的模板。&lt;code&gt;resources/views/blog/index.antlers.html&lt;/code&gt; 可以重用前面的 Collection Tag：&lt;/p&gt;&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{{ title }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{{ content }}

{{ collection:blog limit=&quot;5&quot; }}
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{{ url }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{{ title }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
{{ /collection:blog }}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;單篇文章頁&quot;&gt;單篇文章頁&lt;/h3&gt;&lt;p&gt;單篇文章模板則負責顯示標題、日期、作者與正文：&lt;/p&gt;&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{{ title }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Published on {{ date }} by {{ author:name }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    {{ content }}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;{{ content }}&lt;/code&gt; 是文章正文，&lt;code&gt;{{ author:name }}&lt;/code&gt; 則是讀取作者資料的寫法之一；實際欄位名稱要和你的 Blueprint 一致。&lt;/p&gt;&lt;h2 id=&quot;把重複內容抽成-Partial&quot;&gt;把重複內容抽成 Partial&lt;/h2&gt;&lt;p&gt;文章列表會同時出現在首頁和索引頁。若兩邊都直接複製同一段模板，日後改一個 HTML class 就要改兩次，久了會養出兩份長得很像、脾氣卻不同的程式碼。&lt;/p&gt;&lt;p&gt;在 &lt;code&gt;resources/views/blog/&lt;/code&gt; 建立 &lt;code&gt;_listing.antlers.html&lt;/code&gt;，底線是常見的 partial 命名約定：&lt;/p&gt;&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    {{ collection:blog limit=&quot;5&quot; }}
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{{ url }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{{ title }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    {{ /collection:blog }}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;頁面中再引用它：&lt;/p&gt;&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;{{ partial:blog/_listing }}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Partial 是可重用的模板片段，不是完整頁面。把列表集中管理後，首頁和索引頁就能共享同一份輸出邏輯。&lt;/p&gt;&lt;h2 id=&quot;加上導覽列&quot;&gt;加上導覽列&lt;/h2&gt;&lt;p&gt;如果網站有 Pages 集合，可以使用 Nav Tag 產生導覽：&lt;/p&gt;&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;nav&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    {{ nav from=&quot;pages&quot; include_home=&quot;true&quot; }}
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{{ url }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{{ title }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    {{ /nav }}
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;nav&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;把這段放進 Layout，所有套用該 Layout 的頁面就能共用導覽列。樣式可以之後再加，先讓資料流動起來；CSS 不會因為等五分鐘而生氣，但你可能會。&lt;/p&gt;&lt;h2 id=&quot;用-Blueprint-增加精選圖片&quot;&gt;用 Blueprint 增加精選圖片&lt;/h2&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/IIB9bVr1I3-240.webp 240w, https://kamadiam.com/img/built/IIB9bVr1I3-320.webp 320w, https://kamadiam.com/img/built/IIB9bVr1I3-480.webp 480w, https://kamadiam.com/img/built/IIB9bVr1I3-640.webp 640w, https://kamadiam.com/img/built/IIB9bVr1I3-672.webp 672w, https://kamadiam.com/img/built/IIB9bVr1I3-800.webp 800w, https://kamadiam.com/img/built/IIB9bVr1I3-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/IIB9bVr1I3-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;334&quot; srcset=&quot;https://kamadiam.com/img/built/IIB9bVr1I3-240.png 240w, https://kamadiam.com/img/built/IIB9bVr1I3-320.png 320w, https://kamadiam.com/img/built/IIB9bVr1I3-480.png 480w, https://kamadiam.com/img/built/IIB9bVr1I3-640.png 640w, https://kamadiam.com/img/built/IIB9bVr1I3-672.png 672w, https://kamadiam.com/img/built/IIB9bVr1I3-800.png 800w, https://kamadiam.com/img/built/IIB9bVr1I3-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/IP6RYRqgTv-240.webp 240w, https://kamadiam.com/img/built/IP6RYRqgTv-320.webp 320w, https://kamadiam.com/img/built/IP6RYRqgTv-480.webp 480w, https://kamadiam.com/img/built/IP6RYRqgTv-640.webp 640w, https://kamadiam.com/img/built/IP6RYRqgTv-672.webp 672w, https://kamadiam.com/img/built/IP6RYRqgTv-800.webp 800w, https://kamadiam.com/img/built/IP6RYRqgTv-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/IP6RYRqgTv-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;554&quot; srcset=&quot;https://kamadiam.com/img/built/IP6RYRqgTv-240.png 240w, https://kamadiam.com/img/built/IP6RYRqgTv-320.png 320w, https://kamadiam.com/img/built/IP6RYRqgTv-480.png 480w, https://kamadiam.com/img/built/IP6RYRqgTv-640.png 640w, https://kamadiam.com/img/built/IP6RYRqgTv-672.png 672w, https://kamadiam.com/img/built/IP6RYRqgTv-800.png 800w, https://kamadiam.com/img/built/IP6RYRqgTv-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;Blueprint 用來定義集合或頁面的欄位。你可以在 &lt;code&gt;blog&lt;/code&gt; 集合的 Blueprint 增加 &lt;code&gt;featured_image&lt;/code&gt;，選擇適合圖片資產的欄位型別，並限制單篇文章的圖片數量。&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/5b_EL8GYWm-240.webp 240w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/5b_EL8GYWm-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;240&quot; height=&quot;177&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/A7fMX3qceb-240.webp 240w, https://kamadiam.com/img/built/A7fMX3qceb-320.webp 320w, https://kamadiam.com/img/built/A7fMX3qceb-480.webp 480w, https://kamadiam.com/img/built/A7fMX3qceb-640.webp 640w, https://kamadiam.com/img/built/A7fMX3qceb-672.webp 672w, https://kamadiam.com/img/built/A7fMX3qceb-800.webp 800w, https://kamadiam.com/img/built/A7fMX3qceb-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/A7fMX3qceb-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;557&quot; srcset=&quot;https://kamadiam.com/img/built/A7fMX3qceb-240.png 240w, https://kamadiam.com/img/built/A7fMX3qceb-320.png 320w, https://kamadiam.com/img/built/A7fMX3qceb-480.png 480w, https://kamadiam.com/img/built/A7fMX3qceb-640.png 640w, https://kamadiam.com/img/built/A7fMX3qceb-672.png 672w, https://kamadiam.com/img/built/A7fMX3qceb-800.png 800w, https://kamadiam.com/img/built/A7fMX3qceb-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/UTPL2vgdCR-240.webp 240w, https://kamadiam.com/img/built/UTPL2vgdCR-320.webp 320w, https://kamadiam.com/img/built/UTPL2vgdCR-480.webp 480w, https://kamadiam.com/img/built/UTPL2vgdCR-640.webp 640w, https://kamadiam.com/img/built/UTPL2vgdCR-672.webp 672w, https://kamadiam.com/img/built/UTPL2vgdCR-800.webp 800w, https://kamadiam.com/img/built/UTPL2vgdCR-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/UTPL2vgdCR-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;452&quot; srcset=&quot;https://kamadiam.com/img/built/UTPL2vgdCR-240.png 240w, https://kamadiam.com/img/built/UTPL2vgdCR-320.png 320w, https://kamadiam.com/img/built/UTPL2vgdCR-480.png 480w, https://kamadiam.com/img/built/UTPL2vgdCR-640.png 640w, https://kamadiam.com/img/built/UTPL2vgdCR-672.png 672w, https://kamadiam.com/img/built/UTPL2vgdCR-800.png 800w, https://kamadiam.com/img/built/UTPL2vgdCR-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;設定欄位時，請分清楚「顯示名稱」和「Handle」。模板會使用 Handle，例如 &lt;code&gt;featured_image&lt;/code&gt;。圖片的替代文字也應該在內容編輯時填好，讓無法看見圖片的讀者仍然知道它代表什麼。&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/p4DTO5Il-R-240.webp 240w, https://kamadiam.com/img/built/p4DTO5Il-R-320.webp 320w, https://kamadiam.com/img/built/p4DTO5Il-R-480.webp 480w, https://kamadiam.com/img/built/p4DTO5Il-R-640.webp 640w, https://kamadiam.com/img/built/p4DTO5Il-R-672.webp 672w, https://kamadiam.com/img/built/p4DTO5Il-R-800.webp 800w, https://kamadiam.com/img/built/p4DTO5Il-R-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/p4DTO5Il-R-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;235&quot; srcset=&quot;https://kamadiam.com/img/built/p4DTO5Il-R-240.png 240w, https://kamadiam.com/img/built/p4DTO5Il-R-320.png 320w, https://kamadiam.com/img/built/p4DTO5Il-R-480.png 480w, https://kamadiam.com/img/built/p4DTO5Il-R-640.png 640w, https://kamadiam.com/img/built/p4DTO5Il-R-672.png 672w, https://kamadiam.com/img/built/p4DTO5Il-R-800.png 800w, https://kamadiam.com/img/built/p4DTO5Il-R-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/qeSfr4KQ_y-240.webp 240w, https://kamadiam.com/img/built/qeSfr4KQ_y-320.webp 320w, https://kamadiam.com/img/built/qeSfr4KQ_y-480.webp 480w, https://kamadiam.com/img/built/qeSfr4KQ_y-640.webp 640w, https://kamadiam.com/img/built/qeSfr4KQ_y-672.webp 672w, https://kamadiam.com/img/built/qeSfr4KQ_y-800.webp 800w, https://kamadiam.com/img/built/qeSfr4KQ_y-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/qeSfr4KQ_y-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;150&quot; srcset=&quot;https://kamadiam.com/img/built/qeSfr4KQ_y-240.png 240w, https://kamadiam.com/img/built/qeSfr4KQ_y-320.png 320w, https://kamadiam.com/img/built/qeSfr4KQ_y-480.png 480w, https://kamadiam.com/img/built/qeSfr4KQ_y-640.png 640w, https://kamadiam.com/img/built/qeSfr4KQ_y-672.png 672w, https://kamadiam.com/img/built/qeSfr4KQ_y-800.png 800w, https://kamadiam.com/img/built/qeSfr4KQ_y-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/Ne-fvxMxAL-240.webp 240w, https://kamadiam.com/img/built/Ne-fvxMxAL-320.webp 320w, https://kamadiam.com/img/built/Ne-fvxMxAL-480.webp 480w, https://kamadiam.com/img/built/Ne-fvxMxAL-640.webp 640w, https://kamadiam.com/img/built/Ne-fvxMxAL-672.webp 672w, https://kamadiam.com/img/built/Ne-fvxMxAL-800.webp 800w, https://kamadiam.com/img/built/Ne-fvxMxAL-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/Ne-fvxMxAL-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;394&quot; srcset=&quot;https://kamadiam.com/img/built/Ne-fvxMxAL-240.png 240w, https://kamadiam.com/img/built/Ne-fvxMxAL-320.png 320w, https://kamadiam.com/img/built/Ne-fvxMxAL-480.png 480w, https://kamadiam.com/img/built/Ne-fvxMxAL-640.png 640w, https://kamadiam.com/img/built/Ne-fvxMxAL-672.png 672w, https://kamadiam.com/img/built/Ne-fvxMxAL-800.png 800w, https://kamadiam.com/img/built/Ne-fvxMxAL-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/PDGDuepy3o-240.webp 240w, https://kamadiam.com/img/built/PDGDuepy3o-320.webp 320w, https://kamadiam.com/img/built/PDGDuepy3o-480.webp 480w, https://kamadiam.com/img/built/PDGDuepy3o-640.webp 640w, https://kamadiam.com/img/built/PDGDuepy3o-672.webp 672w, https://kamadiam.com/img/built/PDGDuepy3o-800.webp 800w, https://kamadiam.com/img/built/PDGDuepy3o-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/PDGDuepy3o-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;643&quot; srcset=&quot;https://kamadiam.com/img/built/PDGDuepy3o-240.png 240w, https://kamadiam.com/img/built/PDGDuepy3o-320.png 320w, https://kamadiam.com/img/built/PDGDuepy3o-480.png 480w, https://kamadiam.com/img/built/PDGDuepy3o-640.png 640w, https://kamadiam.com/img/built/PDGDuepy3o-672.png 672w, https://kamadiam.com/img/built/PDGDuepy3o-800.png 800w, https://kamadiam.com/img/built/PDGDuepy3o-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;在文章模板中輸出圖片時，欄位的實際回傳格式會受 Blueprint 和資產設定影響。最基本的概念如下：&lt;/p&gt;&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{{ featured_image }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{{ featured_image:alt }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果專案使用資產陣列或需要圖片轉換，請依官方 Assets 文件和實際欄位輸出調整模板，不要直接照抄一段不符合資料格式的範例。&lt;/p&gt;&lt;h2 id=&quot;StatamicWordPress-與-11ty-怎麼選?&quot;&gt;Statamic、WordPress 與 11ty 怎麼選？&lt;/h2&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/XO8O-kttxA-240.webp 240w, https://kamadiam.com/img/built/XO8O-kttxA-320.webp 320w, https://kamadiam.com/img/built/XO8O-kttxA-480.webp 480w, https://kamadiam.com/img/built/XO8O-kttxA-640.webp 640w, https://kamadiam.com/img/built/XO8O-kttxA-672.webp 672w, https://kamadiam.com/img/built/XO8O-kttxA-800.webp 800w, https://kamadiam.com/img/built/XO8O-kttxA-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/XO8O-kttxA-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;465&quot; srcset=&quot;https://kamadiam.com/img/built/XO8O-kttxA-240.png 240w, https://kamadiam.com/img/built/XO8O-kttxA-320.png 320w, https://kamadiam.com/img/built/XO8O-kttxA-480.png 480w, https://kamadiam.com/img/built/XO8O-kttxA-640.png 640w, https://kamadiam.com/img/built/XO8O-kttxA-672.png 672w, https://kamadiam.com/img/built/XO8O-kttxA-800.png 800w, https://kamadiam.com/img/built/XO8O-kttxA-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/Ue3P_eqQTv-240.webp 240w, https://kamadiam.com/img/built/Ue3P_eqQTv-320.webp 320w, https://kamadiam.com/img/built/Ue3P_eqQTv-480.webp 480w, https://kamadiam.com/img/built/Ue3P_eqQTv-640.webp 640w, https://kamadiam.com/img/built/Ue3P_eqQTv-672.webp 672w, https://kamadiam.com/img/built/Ue3P_eqQTv-800.webp 800w, https://kamadiam.com/img/built/Ue3P_eqQTv-1200.webp 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/Ue3P_eqQTv-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;465&quot; srcset=&quot;https://kamadiam.com/img/built/Ue3P_eqQTv-240.png 240w, https://kamadiam.com/img/built/Ue3P_eqQTv-320.png 320w, https://kamadiam.com/img/built/Ue3P_eqQTv-480.png 480w, https://kamadiam.com/img/built/Ue3P_eqQTv-640.png 640w, https://kamadiam.com/img/built/Ue3P_eqQTv-672.png 672w, https://kamadiam.com/img/built/Ue3P_eqQTv-800.png 800w, https://kamadiam.com/img/built/Ue3P_eqQTv-1200.png 1200w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://kamadiam.com/img/built/UAjQ2k0erw-240.webp 240w, https://kamadiam.com/img/built/UAjQ2k0erw-320.webp 320w, https://kamadiam.com/img/built/UAjQ2k0erw-480.webp 480w, https://kamadiam.com/img/built/UAjQ2k0erw-640.webp 640w, https://kamadiam.com/img/built/UAjQ2k0erw-672.webp 672w, https://kamadiam.com/img/built/UAjQ2k0erw-800.webp 800w, https://kamadiam.com/img/built/UAjQ2k0erw-1030.webp 1030w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;img src=&quot;https://kamadiam.com/img/built/UAjQ2k0erw-240.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; width=&quot;1030&quot; height=&quot;1490&quot; srcset=&quot;https://kamadiam.com/img/built/UAjQ2k0erw-240.png 240w, https://kamadiam.com/img/built/UAjQ2k0erw-320.png 320w, https://kamadiam.com/img/built/UAjQ2k0erw-480.png 480w, https://kamadiam.com/img/built/UAjQ2k0erw-640.png 640w, https://kamadiam.com/img/built/UAjQ2k0erw-672.png 672w, https://kamadiam.com/img/built/UAjQ2k0erw-800.png 800w, https://kamadiam.com/img/built/UAjQ2k0erw-1030.png 1030w&quot; sizes=&quot;(max-width: 768px) 100vw, 65ch&quot;&gt;&lt;/picture&gt;&lt;/p&gt;&lt;p&gt;三者都能拿來做網站，但解決的問題不同：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Statamic&lt;/strong&gt;：適合需要控制面板、內容集合、欄位藍圖，又希望內容與設定能以檔案管理的團隊。它建立在 Laravel 上，前端可以使用 Antlers，也能依專案選擇其他做法。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;WordPress&lt;/strong&gt;：適合想快速使用成熟後台、佈景主題和外掛生態的使用者。彈性很高，但網站的實際行為會取決於佈景主題、外掛和主機環境。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;11ty&lt;/strong&gt;：適合偏好 Markdown、Git 和靜態輸出的開發者。它是靜態網站產生器，不是內建內容編輯控制面的 CMS；需要多人後台時，通常要另外整合服務。&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Statamic 的 flat-file 模式和 11ty 都重視檔案與版本控制，但使用感不同：11ty 偏向建置時把內容產生為靜態檔案；Statamic 則保留 CMS 的管理介面和動態應用程式能力。選擇時先問自己：編輯者需要後台嗎？內容是否需要複雜欄位？部署流程和團隊習慣是哪一種？&lt;/p&gt;&lt;h2 id=&quot;適合誰使用?&quot;&gt;適合誰使用？&lt;/h2&gt;&lt;p&gt;Statamic 適合以下情境：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;內容團隊需要控制面板，但開發團隊想用 Git 管理內容結構和模板。&lt;/li&gt;&lt;li&gt;專案需要自訂 Collection、Blueprint、路由和前端設計。&lt;/li&gt;&lt;li&gt;團隊熟悉 Laravel、PHP 或希望沿用 Laravel 的開發方式。&lt;/li&gt;&lt;li&gt;想從 flat-file 開始，未來再依規模評估資料庫或 Headless 架構。&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;如果你只想寫幾篇 Markdown，並且不需要後台，11ty 可能更直接。如果你希望安裝主題、調整設定後立即上線，WordPress 的現成生態可能更省力。Statamic 的自由度很高，但自由度也代表你需要自己做一些決定；它不是「完全不用想」的 CMS，而是「可以決定要怎麼想」的 CMS。&lt;/p&gt;&lt;h2 id=&quot;結語&quot;&gt;結語&lt;/h2&gt;&lt;p&gt;Statamic 的核心魅力，不只是「不用資料庫」這一句話，而是把 CMS、檔案型內容、版本控制和 Laravel 開發流程接在一起。從 CLI 建立專案，設定 Collection，再用 Antlers 和 Partial 組出頁面，你可以逐步理解每一層，而不是一次吞下一整套黑盒子。&lt;/p&gt;&lt;p&gt;先做一個小部落格，確認內容模型和模板邏輯，再考慮外掛、Starter Kit、圖片處理或部署。網站開發像手沖咖啡：水溫、比例和流程都重要，但第一杯先喝得下去，比研究半天濾杯角度更重要。&lt;/p&gt;&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://statamic.dev/getting-started/quick-start-guide&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Statamic Quick Start Guide&lt;/a&gt;：官方快速入門流程，涵蓋安裝、首頁、Collection 與模板。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://statamic.dev/getting-started/installing/local&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Install Statamic with the CLI&lt;/a&gt;：官方 CLI 安裝需求與 &lt;code&gt;statamic new&lt;/code&gt; 建站流程。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://statamic.dev/getting-started/installing/laravel-herd&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Install Statamic with Laravel Herd&lt;/a&gt;：官方 Herd 本機環境安裝說明。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://statamic.dev/getting-started/core-concepts&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Core Concepts&lt;/a&gt;：官方說明 flat-file 模式、內容管理與架構取捨。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://statamic.dev/content-modeling/collections&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Collections&lt;/a&gt;：官方說明 Collection、Entry 儲存方式與路由。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://statamic.dev/frontend/antlers&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Antlers Templates&lt;/a&gt;：官方 Antlers 模板語法、檔案位置與 Layout 說明。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://statamic.dev/starter-kits/overview&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Starter Kits Overview&lt;/a&gt;：官方說明 Starter Kits 和 WordPress themes 的差異。&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>SOLID 原則 PHP 實戰：五大設計原則速查 + 設計模式對照</title>
    <link href="https://kamadiam.com/solid-principles-in-php/" />
    <updated>2026-08-29T00:00:00Z</updated>
    <id>https://kamadiam.com/solid-principles-in-php/</id>
    <content type="html">&lt;p&gt;寫程式不難，難的是半年後回頭看，還敢不敢改自己的程式碼。當一個類別同時算薪水、寫資料庫、寄信，甚至順便幫你煮咖啡，需求一變就會像耳機線一樣打結。這時候，SOLID 原則可以當一張設計地圖。&lt;/p&gt;&lt;p&gt;這篇會用 PHP 範例帶你理解 SOLID 的五個原則：它們各自想解決什麼問題、怎麼拆出比較健康的設計，以及什麼時候不必硬套。讀完後，你應該能看出程式碼「哪裡開始變胖」，也知道該從哪裡下刀。&lt;/p&gt;&lt;h2 id=&quot;SOLID-速查表&quot;&gt;SOLID 速查表&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;字母&lt;/th&gt;&lt;th&gt;原則&lt;/th&gt;&lt;th&gt;白話&lt;/th&gt;&lt;th&gt;違反時的症狀&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;S&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Single Responsibility&lt;/td&gt;&lt;td&gt;一個類別只有一個改變的理由&lt;/td&gt;&lt;td&gt;改 A 功能卻壞 B 功能&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;O&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Open/Closed&lt;/td&gt;&lt;td&gt;對擴充開放、對修改封閉&lt;/td&gt;&lt;td&gt;每加需求就改核心類別&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;L&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Liskov Substitution&lt;/td&gt;&lt;td&gt;子類別可替換父類別&lt;/td&gt;&lt;td&gt;繼承後行為不一致&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;I&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Interface Segregation&lt;/td&gt;&lt;td&gt;介面要小而專&lt;/td&gt;&lt;td&gt;被迫實作用不到的方法&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;D&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Dependency Inversion&lt;/td&gt;&lt;td&gt;依賴抽象，不依賴具體&lt;/td&gt;&lt;td&gt;高層直接 new 低層實作&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;blockquote&gt;&lt;p&gt;延伸閱讀：&lt;a href=&quot;https://kamadiam.com/php-object-and-class/&quot;&gt;PHP 類別入門&lt;/a&gt; · &lt;a href=&quot;https://kamadiam.com/php-basic-tutorial/&quot;&gt;PHP 設計模式系列&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/solid-principles-in-php/#SOLID-%E9%80%9F%E6%9F%A5%E8%A1%A8&quot;&gt;SOLID 速查表&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/solid-principles-in-php/#SOLID-%E6%98%AF%E4%BB%80%E9%BA%BC?&quot;&gt;SOLID 是什麼？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/solid-principles-in-php/#S%E5%96%AE%E4%B8%80%E8%81%B7%E8%B2%AC%E5%8E%9F%E5%89%87SRP&quot;&gt;S：單一職責原則（SRP）&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/solid-principles-in-php/#O%E9%96%8B%E6%94%BE%E5%B0%81%E9%96%89%E5%8E%9F%E5%89%87OCP&quot;&gt;O：開放封閉原則（OCP）&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/solid-principles-in-php/#L%E9%87%8C%E6%B0%8F%E6%9B%BF%E6%8F%9B%E5%8E%9F%E5%89%87LSP&quot;&gt;L：里氏替換原則（LSP）&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/solid-principles-in-php/#I%E4%BB%8B%E9%9D%A2%E9%9A%94%E9%9B%A2%E5%8E%9F%E5%89%87ISP&quot;&gt;I：介面隔離原則（ISP）&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/solid-principles-in-php/#D%E4%BE%9D%E8%B3%B4%E5%8F%8D%E8%BD%89%E5%8E%9F%E5%89%87DIP&quot;&gt;D：依賴反轉原則（DIP）&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/solid-principles-in-php/#SOLID-%E8%88%87%E8%A8%AD%E8%A8%88%E6%A8%A1%E5%BC%8F%E6%80%8E%E9%BA%BC%E5%88%86?&quot;&gt;SOLID 與設計模式怎麼分？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/solid-principles-in-php/#%E5%AF%A6%E5%8B%99%E4%B8%8A%E6%80%8E%E9%BA%BC%E4%BD%BF%E7%94%A8-SOLID?&quot;&gt;實務上怎麼使用 SOLID？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/solid-principles-in-php/#%E7%B8%BD%E7%B5%90&quot;&gt;總結&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/solid-principles-in-php/#%E5%B8%B8%E8%A6%8B-FAQ&quot;&gt;常見 FAQ&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/solid-principles-in-php/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;SOLID-是什麼?&quot;&gt;SOLID 是什麼？&lt;/h2&gt;&lt;p&gt;SOLID 是五個物件導向設計原則英文名稱的首字母：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;S — Single Responsibility Principle（單一職責原則）&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;O — Open/Closed Principle（開放封閉原則）&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;L — Liskov Substitution Principle（里氏替換原則）&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;I — Interface Segregation Principle（介面隔離原則）&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;D — Dependency Inversion Principle（依賴反轉原則）&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;它們不是 PHP 的語法，也不是一份「照著做就永遠正確」的檢查表，而是幫助你降低耦合、控制變動範圍的思考工具。換句話說，SOLID 的重點不是把類別拆到像樂高散落一地，而是讓每個變動有比較清楚的落點。&lt;/p&gt;&lt;h2 id=&quot;S單一職責原則SRP&quot;&gt;S：單一職責原則（SRP）&lt;/h2&gt;&lt;p&gt;單一職責原則常被簡化成「一個類別只做一件事」。這句話方向沒錯，但還不夠精準。Robert C. Martin 對 SRP 的經典說法是：一個模組應該只有一個「改變的理由」。&lt;/p&gt;&lt;p&gt;這裡的「職責」不是方法數量，而是誰會要求它改變。薪資規則由人資提出修改、資料庫格式由後端提出修改、畫面格式由前端提出修改；如果三種需求都集中在 &lt;code&gt;Employee&lt;/code&gt;，它就背了太多不同的改變理由。&lt;/p&gt;&lt;h3 id=&quot;容易失控的寫法&quot;&gt;容易失控的寫法&lt;/h3&gt;&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;EmployeeService&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;calculateSalary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name type-declaration&quot;&gt;Employee&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$employee&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;int&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$employee&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;baseSalary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$employee&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bonus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name type-declaration&quot;&gt;Employee&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$employee&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token comment&quot;&gt;// 寫入資料庫&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;renderProfile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name type-declaration&quot;&gt;Employee&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$employee&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token comment&quot;&gt;// 組合 HTML&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;p&gt;&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$employee&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;/p&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;這個類別現在知道薪資規則、資料儲存和 HTML。任何一項需求變更，都可能碰到同一個檔案。類別不是不能有三個方法，而是這三個方法的變動原因彼此無關。&lt;/p&gt;&lt;h3 id=&quot;讓職責各就各位&quot;&gt;讓職責各就各位&lt;/h3&gt;&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;SalaryCalculator&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;calculate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name type-declaration&quot;&gt;Employee&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$employee&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;int&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$employee&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;baseSalary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$employee&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bonus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;EmployeeRepository&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name type-declaration&quot;&gt;Employee&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$employee&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token comment&quot;&gt;// 將員工資料寫入資料庫&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;EmployeeProfileRenderer&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name type-declaration&quot;&gt;Employee&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$employee&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;p&gt;&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$employee&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;&amp;lt;/p&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;拆開後，薪資規則、儲存方式與顯示格式各自有清楚的責任邊界，也比較容易單獨測試。SRP 不是「每個類別只能有一個 public method」，而是「不要把不同的變動原因綁在一起」。&lt;/p&gt;&lt;h2 id=&quot;O開放封閉原則OCP&quot;&gt;O：開放封閉原則（OCP）&lt;/h2&gt;&lt;p&gt;開放封閉原則是：軟體實體應該對擴充開放，對修改封閉。意思不是原始碼永遠不能改，而是當你新增一種行為時，最好能透過新增實作來完成，避免反覆修改已經穩定的核心流程。&lt;/p&gt;&lt;h3 id=&quot;if-越長,咖啡越苦&quot;&gt;&lt;code&gt;if&lt;/code&gt; 越長，咖啡越苦&lt;/h3&gt;&lt;p&gt;假設結帳服務用條件判斷處理每種折扣：&lt;/p&gt;&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;discountFor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword type-hint&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$memberType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword type-hint&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$amount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$memberType&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;regular&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$memberType&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;vip&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword type-casting&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$amount&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$memberType&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;staff&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword type-casting&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$amount&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;剛開始只有兩種會員，看起來很方便。等到加入生日折扣、活動折扣、合作夥伴折扣，這個函式就會變成一條需要小心穿越的 &lt;code&gt;if&lt;/code&gt; 迷宮。迷宮本身沒有錯，但維護它通常不會讓人心情變好。&lt;/p&gt;&lt;h3 id=&quot;將變動的規則抽成策略&quot;&gt;將變動的規則抽成策略&lt;/h3&gt;&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;DiscountPolicy&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;discountFor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword type-hint&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$amount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;VipDiscount&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DiscountPolicy&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;discountFor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword type-hint&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$amount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;int&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword type-casting&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$amount&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;StaffDiscount&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DiscountPolicy&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;discountFor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword type-hint&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$amount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;int&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword type-casting&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$amount&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;Checkout&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name type-declaration&quot;&gt;DiscountPolicy&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$discountPolicy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword type-hint&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$amount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;int&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$amount&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;discountPolicy&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;discountFor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$amount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;新增折扣規則時，可以新增另一個 &lt;code&gt;DiscountPolicy&lt;/code&gt; 實作，&lt;code&gt;Checkout&lt;/code&gt; 不必跟著修改。這就是常見的 Strategy（策略）做法，也是 OCP 的一種實現方式。&lt;/p&gt;&lt;p&gt;不過，OCP 不代表每一個小函式都要先抽介面。尚未出現變動點時過度抽象，反而會增加理解成本。先觀察真正會變的地方，再決定要不要抽象，通常比較務實。&lt;/p&gt;&lt;h2 id=&quot;L里氏替換原則LSP&quot;&gt;L：里氏替換原則（LSP）&lt;/h2&gt;&lt;p&gt;里氏替換原則要求：如果程式碼期待的是某個父型別或介面，那麼換成它的子型別或實作後，原本的正確性與使用方式仍然成立。&lt;/p&gt;&lt;p&gt;重點不是「有 &lt;code&gt;extends&lt;/code&gt; 就算繼承成功」，而是子類別必須遵守父類別對外做出的契約。若父類別承諾「呼叫 &lt;code&gt;withdraw()&lt;/code&gt; 會扣款」，子類別就不能突然改成「遇到某種帳戶就丟出不支援例外」，否則呼叫端就得先猜對方是哪一種物件。&lt;/p&gt;&lt;h3 id=&quot;會讓呼叫端踩雷的繼承&quot;&gt;會讓呼叫端踩雷的繼承&lt;/h3&gt;&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;Bird&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;fly&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token comment&quot;&gt;// 飛行&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;Penguin&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Bird&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;fly&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LogicException&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;企鵝不會飛&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;letBirdFly&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name type-declaration&quot;&gt;Bird&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$bird&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token variable&quot;&gt;$bird&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fly&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;letBirdFly()&lt;/code&gt; 接受 &lt;code&gt;Bird&lt;/code&gt;，照它的契約自然會呼叫 &lt;code&gt;fly()&lt;/code&gt;。傳入 &lt;code&gt;Penguin&lt;/code&gt; 後卻必定失敗，代表這個繼承關係只是在語法上成立，在行為上卻不成立。&lt;/p&gt;&lt;h3 id=&quot;讓抽象符合真正能力&quot;&gt;讓抽象符合真正能力&lt;/h3&gt;&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;Animal&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;Flyable&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;fly&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;Sparrow&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Animal&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Flyable&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;fly&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token comment&quot;&gt;// 飛行&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;Penguin&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Animal&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// 企鵝是動物，但不是 Flyable&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;這裡不是把企鵝排除在鳥類之外，而是避免對「會飛」做出錯誤承諾。設計抽象時，先問「這個型別真的能保證什麼行為？」比先問「它是不是某某的子類別？」更重要。&lt;/p&gt;&lt;h2 id=&quot;I介面隔離原則ISP&quot;&gt;I：介面隔離原則（ISP）&lt;/h2&gt;&lt;p&gt;介面隔離原則主張：不要讓使用者依賴它用不到的方法。這裡的使用者可以是實作介面的類別，也可以是呼叫該介面的其他程式碼。&lt;/p&gt;&lt;h3 id=&quot;一個什麼都管的介面&quot;&gt;一個什麼都管的介面&lt;/h3&gt;&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;Worker&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;cook&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;clean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果 &lt;code&gt;Developer&lt;/code&gt; 只需要寫程式與測試，卻被迫實作 &lt;code&gt;cook()&lt;/code&gt; 和 &lt;code&gt;clean()&lt;/code&gt;，介面就太胖了。更麻煩的是，介面新增一個方法時，所有實作者都可能被迫同步修改。&lt;/p&gt;&lt;h3 id=&quot;拆成能組合的小介面&quot;&gt;拆成能組合的小介面&lt;/h3&gt;&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;Coder&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;Tester&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;Developer&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Coder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Tester
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token comment&quot;&gt;// 寫程式&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token comment&quot;&gt;// 執行測試&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;小介面讓依賴關係更精準，也讓類別可以用組合表達能力。介面不是自助餐，不需要把所有方法都端上桌；端太多，最後通常只會剩下沒人想吃的抽象。&lt;/p&gt;&lt;h2 id=&quot;D依賴反轉原則DIP&quot;&gt;D：依賴反轉原則（DIP）&lt;/h2&gt;&lt;p&gt;依賴反轉原則有兩層意思：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;高層模組不應直接依賴低層模組；兩者都應依賴抽象。&lt;/li&gt;&lt;li&gt;抽象不應依賴細節；細節應依賴抽象。&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;高層模組是業務規則，例如「註冊使用者」；低層模組則可能是 MySQL、檔案系統或第三方 API。業務規則不需要知道資料是存在哪一台資料庫，才能完成自己的工作。&lt;/p&gt;&lt;h3 id=&quot;把具體資料庫寫死&quot;&gt;把具體資料庫寫死&lt;/h3&gt;&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;MySqlUserRepository&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword type-hint&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$email&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token comment&quot;&gt;// 寫入 MySQL&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;RegisterUser&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name type-declaration&quot;&gt;MySqlUserRepository&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$repository&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;repository&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MySqlUserRepository&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword type-hint&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$email&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$email&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;RegisterUser&lt;/code&gt; 自己建立 &lt;code&gt;MySqlUserRepository&lt;/code&gt;，所以測試時很難替換成記憶體版本，未來改用其他儲存方式也得修改業務類別。&lt;/p&gt;&lt;h3 id=&quot;讓高層依賴抽象&quot;&gt;讓高層依賴抽象&lt;/h3&gt;&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;UserRepository&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword type-hint&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$email&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;MySqlUserRepository&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UserRepository&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword type-hint&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$email&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token comment&quot;&gt;// 寫入 MySQL&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;RegisterUser&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name type-declaration&quot;&gt;UserRepository&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$repository&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword type-hint&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$email&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword return-type&quot;&gt;void&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$email&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;現在 &lt;code&gt;RegisterUser&lt;/code&gt; 只依賴 &lt;code&gt;UserRepository&lt;/code&gt; 這個抽象，具體實作透過建構子注入。測試時可以傳入一個測試用 repository；正式環境則傳入 &lt;code&gt;MySqlUserRepository&lt;/code&gt;。這通常也被稱為依賴注入，但要注意：&lt;strong&gt;依賴注入是達成解耦的一種手法，DIP 是設計原則&lt;/strong&gt;，兩者不是同義詞。&lt;/p&gt;&lt;h2 id=&quot;SOLID-與設計模式怎麼分?&quot;&gt;SOLID 與設計模式怎麼分？&lt;/h2&gt;&lt;p&gt;SOLID 是設計時的原則；設計模式則是針對常見問題整理出的解法。兩者可以互相呼應，但不是一對一的配對表。&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;原則&lt;/th&gt;&lt;th&gt;常見呼應方式&lt;/th&gt;&lt;th&gt;重點&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;SRP&lt;/td&gt;&lt;td&gt;Facade、Repository&lt;/td&gt;&lt;td&gt;把不同變動原因分開&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;OCP&lt;/td&gt;&lt;td&gt;Strategy、Decorator&lt;/td&gt;&lt;td&gt;新增行為時減少修改核心&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LSP&lt;/td&gt;&lt;td&gt;多型、合約測試&lt;/td&gt;&lt;td&gt;子型別遵守抽象契約&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ISP&lt;/td&gt;&lt;td&gt;小型角色介面&lt;/td&gt;&lt;td&gt;只依賴真正需要的能力&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;DIP&lt;/td&gt;&lt;td&gt;Dependency Injection、Factory&lt;/td&gt;&lt;td&gt;高層依賴抽象&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;例如，Factory 解決的是「物件怎麼建立」，Singleton 解決的是「限制實例數量」。它們都可能出現在某個遵循 DIP 的設計裡，但使用 Singleton 不會自動讓程式變得 SOLID；全域狀態該難測，還是會難測。&lt;/p&gt;&lt;h2 id=&quot;實務上怎麼使用-SOLID?&quot;&gt;實務上怎麼使用 SOLID？&lt;/h2&gt;&lt;p&gt;SOLID 最適合拿來處理「已經看見的變動」與「正在造成痛苦的耦合」，不適合當成開工前的儀式。你可以用下面幾個問題做快速檢查：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;這個類別是否同時受到不同角色的需求影響？如果是，回頭看 SRP。&lt;/li&gt;&lt;li&gt;每次新增類型都要修改同一串條件判斷嗎？如果是，考慮 OCP。&lt;/li&gt;&lt;li&gt;子類別是否需要丟出「這個方法我不支援」的例外？如果是，檢查 LSP。&lt;/li&gt;&lt;li&gt;類別是否被迫實作或依賴一大堆用不到的方法？如果是，看看 ISP。&lt;/li&gt;&lt;li&gt;業務邏輯是否直接 &lt;code&gt;new&lt;/code&gt; 出資料庫、郵件服務或第三方 SDK？如果是，考慮 DIP。&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;最後也別忘了 YAGNI：還沒有需求、沒有變動跡象時，先寫清楚簡單的程式碼，通常比預先蓋一座抽象城堡更好維護。SOLID 的目標是降低變更成本，不是增加類別數量。類別多到需要地圖才能找到入口，那就不是 SOLID，是迷宮設計。&lt;/p&gt;&lt;h2 id=&quot;總結&quot;&gt;總結&lt;/h2&gt;&lt;p&gt;SOLID 五原則可以濃縮成一句話：讓程式碼的責任清楚、變動可控、依賴可替換，並且讓抽象真正符合它承諾的行為。&lt;/p&gt;&lt;p&gt;你不需要一次重寫整個專案。下一次看到超長類別、巨型 &lt;code&gt;if&lt;/code&gt;、不自然的繼承，先挑一個最痛的地方改善，跑測試，再觀察設計是否更容易理解。好的設計通常不是一杯咖啡喝完突然出現，而是每次修改少一點心驚膽跳。&lt;/p&gt;&lt;h2 id=&quot;常見-FAQ&quot;&gt;常見 FAQ&lt;/h2&gt;&lt;h3 id=&quot;SOLID-一定要五個全用嗎?&quot;&gt;SOLID 一定要五個全用嗎？&lt;/h3&gt;&lt;p&gt;不用。SOLID 是思考工具，不是開工 checklist。先從最痛的地方（通常是 SRP 或 DIP）下手即可。&lt;/p&gt;&lt;h3 id=&quot;SOLID-和設計模式衝突嗎?&quot;&gt;SOLID 和設計模式衝突嗎？&lt;/h3&gt;&lt;p&gt;不衝突。設計模式是具體解法，SOLID 是設計方向。例如 Factory 常配合 DIP 使用，但 Singleton 濫用可能違反 SRP。&lt;/p&gt;&lt;h3 id=&quot;小專案也要-SOLID-嗎?&quot;&gt;小專案也要 SOLID 嗎？&lt;/h3&gt;&lt;p&gt;小腳本、一次性工具不必。當程式碼會被多人維護、需求會持續變動時，SOLID 的投報才明顯。&lt;/p&gt;&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleResponsibilityPrinciple.html&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;The Single Responsibility Principle — Robert C. Martin&lt;/a&gt;：說明 SRP 的「一個改變理由」觀點。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://blog.cleancoder.com/uncle-bob/2014/05/12/TheOpenClosedPrinciple.html&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;The Open Closed Principle — Robert C. Martin&lt;/a&gt;：介紹 OCP 與擴充、修改之間的取捨。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Liskov_substitution_principle&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Liskov Substitution Principle — Wikipedia&lt;/a&gt;：整理里氏替換原則的正式定義與背景。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/en/language.oop5.interfaces.php&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PHP 手冊：物件介面&lt;/a&gt;：查閱 PHP 介面的宣告與實作規則。&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/en/language.oop5.decon.php&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PHP 手冊：建構子與解構子&lt;/a&gt;：查閱範例中建構子注入所使用的 PHP 物件語法。&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>PHP class 與 object 入門：類別、物件、$this 實戰教學</title>
    <link href="https://kamadiam.com/php-object-and-class/" />
    <updated>2026-08-29T00:00:00Z</updated>
    <id>https://kamadiam.com/php-object-and-class/</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;PHP class（類別）&lt;/strong&gt; 是建立 object（物件）的藍圖，定義屬性與方法；&lt;strong&gt;object&lt;/strong&gt; 則是用 &lt;code&gt;new&lt;/code&gt; 依照 class 產生的實例，各自保存自己的資料。物件導向（OOP）把相關的資料和操作資料的程式碼放在一起，讓程式不必像咖啡店的桌面一樣，什麼東西都堆在同一區。&lt;/p&gt;&lt;p&gt;這篇用簡單範例帶你理解 class、object、屬性、方法、&lt;code&gt;$this&lt;/code&gt; 與封裝。讀完後，你應該能看懂基本 OOP 程式，並開始設計小型類別。&lt;/p&gt;&lt;h2 id=&quot;快速參考&quot;&gt;快速參考&lt;/h2&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;概念&lt;/th&gt;&lt;th&gt;說明&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;class&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;定義物件應有的屬性與方法（設計圖）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;object&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;用 &lt;code&gt;new ClassName()&lt;/code&gt; 建立的實例（成品）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;屬性（property）&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;物件的資料，如 &lt;code&gt;$book-&amp;gt;title&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;方法（method）&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;物件的行為，如 &lt;code&gt;$book-&amp;gt;describe()&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;code&gt;$this&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;在方法內代表「目前這個物件」&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;封裝&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;用 &lt;code&gt;private&lt;/code&gt;／&lt;code&gt;protected&lt;/code&gt; 限制外部直接改資料&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class=&quot;table-of-contents&quot;&gt;&lt;h2 id=&quot;目錄&quot;&gt;目錄&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/php-object-and-class/#%E5%BF%AB%E9%80%9F%E5%8F%83%E8%80%83&quot;&gt;快速參考&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/php-object-and-class/#class-%E8%88%87-object-%E5%B7%AE%E5%9C%A8%E5%93%AA?&quot;&gt;class 與 object 差在哪？&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/php-object-and-class/#%E5%BB%BA%E7%AB%8B%E7%AC%AC%E4%B8%80%E5%80%8B-class&quot;&gt;建立第一個 class&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/php-object-and-class/#%E7%94%A8-new-%E5%BB%BA%E7%AB%8B-object&quot;&gt;用 new 建立 object&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/php-object-and-class/#%E5%AF%A6%E6%88%B0%E7%AF%84%E4%BE%8BBook-%E8%88%87-Bookshelf&quot;&gt;實戰範例：Book 與 Bookshelf&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/php-object-and-class/#%E5%B0%81%E8%A3%9D%E8%88%87%E5%8F%AF%E8%A6%8B%E6%80%A7&quot;&gt;封裝與可見性&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/php-object-and-class/#%E5%B8%B8%E8%A6%8B%E5%95%8F%E9%A1%8C&quot;&gt;常見問題&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/php-object-and-class/#%E7%B5%90%E8%AA%9E&quot;&gt;結語&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kamadiam.com/php-object-and-class/#%E5%8F%83%E8%80%83%E8%B3%87%E6%96%99&quot;&gt;參考資料&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;h2 id=&quot;class-與-object-差在哪?&quot;&gt;class 與 object 差在哪？&lt;/h2&gt;&lt;p&gt;生活化比喻：&lt;strong&gt;class 像設計圖，object 像依照設計圖做出來的成品&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;&lt;code&gt;Cake&lt;/code&gt; 類別描述蛋糕有哪些資料（口味、尺寸）和能做什麼（烘烤）。依照它建立的巧克力蛋糕和草莓蛋糕，是兩個不同的 object。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;class&lt;/strong&gt;：定義物件應有的屬性和方法&lt;/li&gt;&lt;li&gt;&lt;strong&gt;object&lt;/strong&gt;：class 建立出來的實例，擁有自己的資料&lt;/li&gt;&lt;li&gt;&lt;strong&gt;實例化&lt;/strong&gt;：用 &lt;code&gt;new&lt;/code&gt; 依照 class 建立 object 的過程&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;建立第一個-class&quot;&gt;建立第一個 class&lt;/h2&gt;&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token php language-php&quot;&gt;&lt;span class=&quot;token delimiter important&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;Cake&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$flavor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;bake&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;正在烘烤 &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;flavor&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39; 口味的蛋糕。&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;flavor&lt;/code&gt;、&lt;code&gt;size&lt;/code&gt; 是&lt;strong&gt;屬性&lt;/strong&gt;，保存物件資料&lt;/li&gt;&lt;li&gt;&lt;code&gt;bake()&lt;/code&gt; 是&lt;strong&gt;方法&lt;/strong&gt;，描述物件行為&lt;/li&gt;&lt;li&gt;&lt;code&gt;$this&lt;/code&gt; 代表「目前正在呼叫這個方法的物件」&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;用-new-建立-object&quot;&gt;用 &lt;code&gt;new&lt;/code&gt; 建立 object&lt;/h2&gt;&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$chocolateCake&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Cake&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$chocolateCake&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;flavor&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;巧克力&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$chocolateCake&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;大&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token variable&quot;&gt;$chocolateCake&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bake&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;箭頭 &lt;code&gt;-&amp;gt;&lt;/code&gt; 用來存取物件的屬性或方法。同一個 class 可以建立多個彼此獨立的 object：&lt;/p&gt;&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$chocolateCake&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Cake&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$chocolateCake&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;flavor&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;巧克力&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token variable&quot;&gt;$strawberryCake&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Cake&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$strawberryCake&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;flavor&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;草莓&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token variable&quot;&gt;$chocolateCake&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bake&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// 巧克力&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$strawberryCake&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bake&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// 草莓&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;實戰範例Book-與-Bookshelf&quot;&gt;實戰範例：Book 與 Bookshelf&lt;/h2&gt;&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token php language-php&quot;&gt;&lt;span class=&quot;token delimiter important&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;Book&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$author&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;，作者：&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token variable&quot;&gt;$book&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$book&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;哈比人&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$book&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;author&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;J. R. R. 托爾金&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$book&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;describe()&lt;/code&gt; 透過 &lt;code&gt;$this&lt;/code&gt; 取得目前物件的資料，不必另外傳入 &lt;code&gt;$book&lt;/code&gt;。&lt;/p&gt;&lt;h3 id=&quot;物件組合一個-object-管理多個-object&quot;&gt;物件組合：一個 object 管理多個 object&lt;/h3&gt;&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token php language-php&quot;&gt;&lt;span class=&quot;token delimiter important&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;Bookshelf&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$books&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;addBook&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name type-declaration&quot;&gt;Book&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$book&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;books&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$book&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;listBooks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;books&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$book&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$book&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;PHP_EOL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token variable&quot;&gt;$bookshelf&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Bookshelf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$bookshelf&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addBook&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$book&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$bookshelf&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;listBooks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;Bookshelf&lt;/code&gt; 的 &lt;code&gt;books&lt;/code&gt; 陣列放著多個 &lt;code&gt;Book&lt;/code&gt; object——這就是&lt;strong&gt;物件組合（composition）&lt;/strong&gt;。&lt;/p&gt;&lt;h2 id=&quot;封裝與可見性&quot;&gt;封裝與可見性&lt;/h2&gt;&lt;p&gt;前面用 &lt;code&gt;public&lt;/code&gt;，代表類別外也能直接讀寫。實務上通常限制外部直接改資料：&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;修飾符&lt;/th&gt;&lt;th&gt;類別內&lt;/th&gt;&lt;th&gt;子類別&lt;/th&gt;&lt;th&gt;類別外&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;public&lt;/code&gt;&lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;protected&lt;/code&gt;&lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;private&lt;/code&gt;&lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;pre class=&quot;language-php&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-php&quot;&gt;&lt;span class=&quot;token php language-php&quot;&gt;&lt;span class=&quot;token delimiter important&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name-definition class-name&quot;&gt;Book&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;setTitle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;getTitle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token variable&quot;&gt;$book&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token variable&quot;&gt;$book&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setTitle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string single-quoted-string&quot;&gt;&#39;哈比人&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$book&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getTitle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;這就是&lt;strong&gt;封裝&lt;/strong&gt;：把資料和操作規則放在一起，限制外部直接碰觸內部狀態。詳細對照見 &lt;a href=&quot;https://kamadiam.com/php-access-modifiers/&quot;&gt;存取修飾符&lt;/a&gt;。&lt;/p&gt;&lt;h2 id=&quot;常見問題&quot;&gt;常見問題&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Q：class 和 object 一定要一起用嗎？&lt;/strong&gt;&lt;br&gt;A：class 是定義，object 是執行時的實例。沒有 &lt;code&gt;new&lt;/code&gt; 建立 object，class 只是規格，不會自己跑起來。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Q：&lt;code&gt;$this&lt;/code&gt; 和 &lt;code&gt;self&lt;/code&gt; 差在哪？&lt;/strong&gt;&lt;br&gt;A：&lt;code&gt;$this&lt;/code&gt; 指向目前物件實例；&lt;code&gt;self&lt;/code&gt; 指向類別本身（常用於靜態成員）。初學先掌握 &lt;code&gt;$this&lt;/code&gt; 即可。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Q：什麼時候該用 OOP？&lt;/strong&gt;&lt;br&gt;A：當多組資料和函式明顯屬於同一種「事物」時——例如訂單、使用者、書籍。簡單腳本不必硬套 class。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Q：下一步學什麼？&lt;/strong&gt;&lt;br&gt;A：&lt;a href=&quot;https://kamadiam.com/php-access-modifiers/&quot;&gt;存取修飾符&lt;/a&gt; → &lt;a href=&quot;https://kamadiam.com/php-exception-handling/&quot;&gt;try catch&lt;/a&gt; → &lt;a href=&quot;https://kamadiam.com/php-composer-intro/&quot;&gt;Composer&lt;/a&gt; → &lt;a href=&quot;https://kamadiam.com/solid-principles-in-php/&quot;&gt;SOLID&lt;/a&gt;。&lt;/p&gt;&lt;h2 id=&quot;結語&quot;&gt;結語&lt;/h2&gt;&lt;p&gt;PHP OOP 的核心詞彙：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;class&lt;/strong&gt; 定義屬性與方法&lt;/li&gt;&lt;li&gt;&lt;strong&gt;object&lt;/strong&gt; 是 class 的實例&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;new&lt;/code&gt;&lt;/strong&gt; 建立 object&lt;/li&gt;&lt;li&gt;&lt;strong&gt;&lt;code&gt;$this&lt;/code&gt;&lt;/strong&gt; 在方法內代表目前物件&lt;/li&gt;&lt;li&gt;&lt;strong&gt;封裝&lt;/strong&gt; 透過可見性控制資料存取&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;當程式裡有許多互相關聯的資料和函式時，問自己：「這些是不是屬於同一種事物？」如果是，就可能是設計 class 的好時機。&lt;/p&gt;&lt;h2 id=&quot;參考資料&quot;&gt;參考資料&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/en/language.oop5.php&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PHP 官方文件：Classes and Objects&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/en/language.oop5.basic.php&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PHP 官方文件：The Basics&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/en/language.oop5.visibility.php&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PHP 官方文件：Visibility&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.php.net/manual/en/language.oop5.properties.php&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;PHP 官方文件：Properties&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
</feed>