Day 5 講過 .astro 元件不在瀏覽器裡跑,互動可以交給 framework island。只想加一顆計數按鈕或一個展開收合時,載入整包 Vue 或 React island 反而太重;一段原生 ... 就夠了。
計數器、copy 按鈕、展開收合這類小互動,不一定要用 island。判斷時,可以把「這塊要多少 Java...」想成三個檔位:
.astro 靜態 HTML。大部分內容都停在這裡(Day 5)。...,做小互動,沒有反應式狀態。互動需要多少 Java...,就用對應的檔位,不必每次都直接跳到第 3 檔。
Day 5 的結論是:.astro frontmatter(--- 之間)的程式跑在伺服器,build 或收到請求時執行一次就結束。把 onClick 寫在元素上看似合理,但在 Astro 不會動。官方文件也示範了這種寫法:
沿用 Day 5 的執行界線。handleClick 定義在 frontmatter,只會在伺服器端執行,不會送到瀏覽器綁定事件。要讓程式在瀏覽器執行,就把它寫進 ... 標籤,再用 addEventListener 掛事件:
(來源:Astro 官方 astro-syntax 與 client-side-...s 文件,查證日 2026-07-21。)
要在伺服器算的東西寫 frontmatter,要在瀏覽器跑的東西寫 ...。
...Astro 預設會先處理頁面裡的 ...,再送給瀏覽器。官方文件列出其中幾項:
Astro will process... automatically enables Type... support, bundles imports, and processes ...s as type modules. Small ...s may also be inlined.
(Astro 會處理它,自動支援 Type...、打包 import、以 type module 的方式處理;小的腳本也可能直接內嵌。)來源:Astro 官方 client-side-...s 文件,查證日 2026-07-21。
所以你可以直接寫現代 JS 或 Type...、直接 import 本地檔案或 npm 套件,Astro 會幫你打包。處理過的 ... 也在 module 作用域,不是全域;變數不會污染其他腳本,腳本跑一次就結束。
is:inline 可以退出這套處理:加上去後,這段 ... 會原封不動輸出,不轉 Type...、不解析 import;如果它放在會被重複使用的元件裡,每個實例還會各自複製一份。一般情況保留 Astro 的預設處理即可。
我看過一個上線中的多語系品牌官網:package.json 裡裝了 jQuery,頁面的 ... 卻在等待它出現在全域:
同一段 ... 對本地模組用了 import,卻等著 package.json 已列出的 jQuery 出現在全域。整個專案沒有任何地方把 $ 賦值到 window,所以 setTimeout 每 100 毫秒遞迴一次,永遠等不到。
這種寫法延續自 jQuery 常見的使用方式:在 <head> 放一支 CDN ...,全域自然就有 $。把這個習慣搬進有打包工具的專案時,最少改動的做法就是「假設它已經在全域」,程式碼看起來也還是能跑。
在 Astro 裡,更適合的做法是 import $ from 'jquery',讓 Astro 把它打包進這支 ...。套件沒裝好會在 build 時就報錯,不會留下安靜跑在背景的輪詢迴圈。
不過,那段程式只負責在按下按鈕時更換背景色,用原生 ... 修改 style.backgroundColor 就能完成。是否需要整個函式庫,仍要看這個互動落在哪個檔位。
... 完成兩個小互動範例頁 src/pages/demos/native-....astro(網址 /demos/native-...)包含兩個小互動,都用純原生 ... 實作。先看計數器:
按鈕行為放在這段 ...:抓 DOM、掛上 click 監聽,再更新文字。frontmatter 不負責這段瀏覽器行為,整個計數器就這幾行。
第二個是展開/收合,同樣先抓元素、掛監聽、切換 hidden 屬性,並更新 aria-expanded,讓輔助工具也讀得懂:
這頁已通過 build,也能實際操作。兩個互動都停在第 2 檔,能回應操作,沒有需要框架管理的反應式狀態。
原生 ... 和 island 各有適合的互動範圍:
...:小、狀態單純或根本沒狀態、一次性的 DOM 行為。計數器、展開收合、copy 按鈕、捲動回頂端、漸進增強(沒 JS 也能用,有 JS 更順)。textContent = ...、手動加減屬性來追蹤那份狀態,等於自己手刻一個小框架。當你開始在好幾個地方手動同步「DOM 畫面」和「一份資料」,就該升到第 3 檔(island)。只有一兩處要改,一段 ... 就夠了;為了一顆按鈕載入整包 Vue,則超過了互動的實際需求。
onClick 或使用 window。 frontmatter 跑在伺服器,沒有 DOM,也沒有點擊事件。要在瀏覽器發生的行為,一律寫進 ...。... 當成裸 ...。 Astro 預設會用 module 作用域處理、打包並支援 Type...;只有需要原封不動輸出時,才加 is:inline。...。 短期內可以運作,但狀態增加後,手動 DOM 操作會彼此難以同步。這時應依互動需求換成 island。第 2 檔的驗收有三項。要在瀏覽器跑的程式應寫進 ...;frontmatter 留給伺服器端程式。Astro 預設會處理 ...(打包、Type...、module 作用域),只有要退出處理時才用 is:inline。遇到互動需求時,你也應該能判斷它適合第 2 檔(一段原生 ...),還是該升到第 3 檔(framework island)。
第 3 檔的 island 怎麼運作?一顆 Vue 元件加上 client:load 之後,整頁會變成 SPA,還是只有那一塊送出 JS?Day 8 會從「哪一塊、什麼時候才 hydrate」說明 island 的運作方式。
本日程式碼:step-07|只看這天的改動:step-06...step-07
PS 因為無法成功貼文的關係,所以把 script 相關的內容都拿掉了,...指 script。有興趣的讀者請參考 repo 的內容。