客户端指令 client:* 详解
本教程共 56 篇 · 第 27 篇 · 更新于 2026-08-07 · 约 8 分钟阅读
本节目标:学会用 client:* 客户端指令控制框架组件何时在浏览器里水合(hydrate),知道五种指令各自适合什么场景。
客户端指令是什么
默认情况下,你在 Astro 里用的 React、Vue、Svelte 这类框架组件,只会「在服务端」渲染成静态 HTML。这适合不需要交互的纯展示组件,也能避免发任何多余的 JS 给浏览器。
想让组件「活」起来、能被点击或响应事件,就要靠客户端指令(client directive)。它是写在组件标签上的属性,用来决定「组件的 JavaScript 什么时候发到浏览器」。
除了 client:only 之外,所有客户端指令都是这个流程:组件先在服务端渲染出静态 HTML,再根据你选的指令,把 JS 发到浏览器,最后完成水合、变得可交互。
---
// 例:在浏览器里水合框架组件
import InteractiveButton from '../components/InteractiveButton.jsx';
import InteractiveCounter from '../components/InteractiveCounter.jsx';
import InteractiveModal from '../components/InteractiveModal.svelte';
---
<!-- 页面一加载,这个组件的 JS 就开始加载 -->
<InteractiveButton client:load />
<!-- 用户滚动到组件可见,JS 才发到客户端 -->
<InteractiveCounter client:visible />
<!-- 这个组件不在服务端渲染,只在页面加载时于客户端渲染 -->
<InteractiveModal client:only="svelte" />
组件所需的那个框架(React、Svelte 等)运行时会连同组件自己的 JS 一起发过去。如果一页里有多个组件用同一个框架,框架代码只会发一次,不会重复。
五种客户端指令
Astro 提供了五种客户端指令,按「触发时机」从早到晚排列:
client:load:立刻加载
页面一开始加载,组件 JS 就立刻下载并水合。适合页面一打开就必须可交互的关键组件,比如顶部导航的菜单按钮。
<MyReactComponent client:load />
client:idle:浏览器空闲时加载
组件等浏览器「闲下来」再水合。它不会和首屏关键资源抢时间,适合不那么紧急、但迟早要用的交互。
<MySvelteComponent client:idle />
client:visible:进入视口才加载
组件滚到可视区域才开始水合。要是用户一直没滚到它,它就一直不发 JS。对长页里靠下的轮播、评论区特别合适。
<MyVueComponent client:visible />
client:media:满足媒体查询才加载
后面跟一个 CSS 媒体查询字符串。只有查询成立时,组件才在客户端渲染并水合。适合「移动端和桌面端要不同交互」的场景。
<MyComponent client:media="(max-width: 600px)" />
client:only:只在客户端渲染
注意这个最特别。它不在服务端渲染,组件只在浏览器里生成。所以它没有「服务端静态 HTML」兜底,得在 client:only 后面写明框架名。
<MyModal client:only="react" />
它适合那些完全依赖浏览器 API(比如 window、本地存储)的组件。代价是首屏会有一瞬间空白,因为没服务端 HTML 可显示。
Tip大多数场景用
client:load和client:visible就够。把「关键交互」交给 load,把「靠下内容」交给 visible,性能最好。
给交互组件传 props 的限制
从 Astro 组件往框架组件传 props 没问题,但有个前提:传过去的数据必须能「序列化(serialization)」,也就是能转成适合网络传输或存储的格式。
Astro 不是什么结构都能序列化,所以能当 props 传的类型有限。下面这些是被支持的:
- 普通对象(plain object)、
number、string、Array Map、Set、RegExp、Date、BigIntURL、Uint8Array、Uint16Array、Uint32Array、Infinity
像函数(function)这种没法序列化的东西,只能用在组件「服务端渲染」阶段,没法拿去给水合后的交互用。简单说:你没法把函数从服务端传到客户端当 props 用。
---
import TodoList from '../components/TodoList.jsx';
import Counter from '../components/Counter.svelte';
---
<div>
<TodoList initialTodos={["学 Astro", "审 PR"]} />
<Counter startingCount={1} />
</div>
把子内容传给框架组件
在 Astro 组件里,你可以把子内容塞进框架组件,就像用插槽(slot)一样。不过不同框架引用子内容的方式不一样:
- React、Preact、Solid 用名为
children的特殊 prop; - Svelte、Vue 用
<slot />元素。
---
import MyReactSidebar from '../components/MyReactSidebar.jsx';
---
<MyReactSidebar>
<p>这是一个带文字和按钮的侧边栏。</p>
</MyReactSidebar>
你也可以用具名插槽(named slots)把特定子内容分组。对 React、Preact、Solid 来说,kebab-case 的插槽名会转成 camelCase 的 prop;对 Svelte、Vue 则保留原名。
可以混用、嵌套多个框架
同一个 Astro 组件里,能同时导入并渲染多个框架的组件。Astro 靠文件后缀认出该用哪个框架。如果几个框架用了相同后缀(比如 React 和 Preact 都是 .jsx),就需要在配置里额外区分。
---
import MyReactComponent from '../components/MyReactComponent.jsx';
import MySvelteComponent from '../components/MySvelteComponent.svelte';
import MyVueComponent from '../components/MyVueComponent.vue';
---
<div>
<MySvelteComponent />
<MyReactComponent />
<MyVueComponent />
</div>
框架组件里还能再嵌套别的水合组件,递归下去就行。也就是说,你可以整块「应用」都用自己偏爱的框架写,再通过一个父组件渲染到 Astro 页面上。
怎么选:一张决策清单
面对五种指令,记住这条判断链路:
- 页面打开就必须可交互?用
client:load。 - 要交互但不急、别抢首屏?用
client:idle。 - 在长页靠下、用户可能不看?用
client:visible。 - 只在某种屏幕宽度才需要?用
client:media。 - 完全依赖浏览器、没服务端 HTML 也无所谓?用
client:only。
Tip别一股脑全用
client:load。岛屿越多、加载越早,首屏 JS 就越重。Astro 的快,来自「能不发就不发」。
一个常见误区
有人会试着给 Astro 组件加 client:visible,结果直接报错。原因前面提过:Astro 组件是纯 HTML 模板,没有客户端运行时,根本没法水合。
如果你只是想给静态页面加点交互,比如一段点击展开的逻辑,不一定非要上框架组件。在 .astro 文件里写 <script> 标签,那段 JS 会在全局作用域执行,往往就够用了。框架组件更适合「组件本身复杂、内部状态多」的场景。
为什么需要这么多档位
你可能会想:直接全部 client:load 不就行了?问题在于「快」是 Astro 的立身之本。如果一个页面有十个交互组件,全部一加载就水合,浏览器就要立刻下载十份框架代码加组件代码,首屏瞬间变重。
把加载时机拆成不同档位,本质是「按需发 JS」。关键交互立刻给,次要的等空闲,靠下的等看见。用户感知到的,是页面秒开、该动的地方才动。这种「克制」正是群岛架构的精髓。
一张速查表
把五种指令放一起对比,方便你随手翻:
| 指令 | 触发时机 | 适合场景 | 服务端有 HTML 兜底 |
|---|---|---|---|
client:load | 页面一加载就水合 | 关键交互(导航、搜索框) | 有 |
client:idle | 浏览器空闲时水合 | 不急但迟早要用 | 有 |
client:visible | 滚进视口才水合 | 长页靠下(轮播、评论) | 有 |
client:media | 媒体查询成立才水合 | 不同屏幕不同交互 | 有 |
client:only | 只在浏览器渲染 | 强依赖浏览器 API | 无 |
记住一个底线:除 client:only 外,其余四种都是「先出静态 HTML、再发 JS 水合」;client:only 没有服务端 HTML,首屏可能闪一下。能用前四种就别用 client:only。
小结
客户端指令就是「何时发 JS、何时水合」的总开关。load 立刻、idle 空闲、visible 进视口、media 看屏幕、only 只在浏览器。下一章我们看怎么把这些框架真正接入 Astro 项目。