模板指令参考
模板指令是一种特殊的 HTML 属性,可在任何 Astro 组件模板(.astro
文件)内使用,有些也可以在 .mdx
文件中使用。
模板指令用于以某种方式控制元素或组件的行为。模板指令可以启用一些编译器功能,让你的工作更轻松(例如使用 class:list
代替 class
)。或者,指令可以告诉 Astro 编译器对该组件执行特殊操作(例如使用 client:load
进行激活)。
本页介绍了 Astro 中所有可用的模板指令及其工作原理。
要使模板指令有效,它必须:
- 在其名称中包含一个冒号
:
,使用X:Y
的形式(例如:client:load
)。 - 对编译器可见(例如:如果
attr
包含指令,则<X {...attr}>
将不起作用)。
一些模板指令(但不是全部)可以接受自定义值:
<X client:load />
(不接受值)<X class:list={['some-css-class']} />
(接受一个数组)
模板指令永远不会直接包含在组件的最终 HTML 输出中。
常用指令
标题为“常用指令”的部分class:list
标题为“class:list”的部分class:list={...}
接收一个 class 值的数组,并将其转换为一个 class 字符串。这是由 @lukeed 流行的 clsx 辅助库提供支持的。
class:list
接受一个包含多种可能值类型的数组:
string
:添加到元素的class
中Object
:所有真值键都将添加到元素的class
中Array
:被展平false
、null
或undefined
:被跳过
<!-- This --><span class:list={[ 'hello goodbye', { world: true }, [ 'friend' ] ]} /><!-- Becomes --><span class="hello goodbye world friend"></span>
set:html
标题为“set:html”的部分set:html={string}
将一个 HTML 字符串注入到一个元素中,类似于设置 el.innerHTML
。
Astro 不会自动转义该值!请确保你信任该值,或者在将其传递给模板之前已手动进行转义。忘记这样做会使你面临跨站脚本(XSS)攻击的风险。
---const rawHTMLString = "Hello <strong>World</strong>"---<h1>{rawHTMLString}</h1> <!-- Output: <h1>Hello <strong>World</strong></h1> --><h1 set:html={rawHTMLString} /> <!-- Output: <h1>Hello <strong>World</strong></h1> -->
你也可以在 <Fragment>
上使用 set:html
来避免添加不必要的包装元素。这在从 CMS 获取 HTML 时特别有用。
---const cmsContent = await fetchHTMLFromMyCMS();---<Fragment set:html={cmsContent}>
set:html={Promise<string>}
将一个包装在 Promise 中的 HTML 字符串注入到一个元素中。
这可以用于注入存储在外部(例如数据库中)的 HTML。
---import api from '../db/api.js';---<article set:html={api.getArticle(Astro.props.id)}></article>
set:html={Promise<Response>}
将一个 Response 对象注入到一个元素中。
这在使用 fetch()
时最有用。例如,从以前的静态站点生成器中获取旧文章。
<article set:html={fetch('http://example/old-posts/making-soup.html')}></article>
set:html
可以在任何标签上使用,并且不一定需要包含 HTML。例如,在 <script>
标签上与 JSON.stringify()
一起使用,以向你的页面添加 JSON-LD 模式。
<script type="application/ld+json" set:html={JSON.stringify({ "@context": "https://schema.org/", "@type": "Person", name: "Houston", hasOccupation: { "@type": "Occupation", name: "Astronaut" }})}/>
set:text
标题为“set:text”的部分set:text={string}
将一个文本字符串注入到一个元素中,类似于设置 el.innerText
。与 set:html
不同,传递的 string
值会被 Astro 自动转义。
这等同于直接将变量传递到模板表达式中(例如:<div>{someText}</div>
),因此该指令不常用。
客户端指令
标题为“客户端指令”的部分这些指令控制UI 框架组件在页面上如何被激活。
默认情况下,UI 框架组件不会在客户端被激活。如果没有提供 client:*
指令,它的 HTML 会在没有 JavaScript 的情况下被渲染到页面上。
客户端指令只能用在直接导入到 .astro
组件中的 UI 框架组件上。当使用动态标签和通过 components
属性传递的自定义组件时,不支持激活指令。
client:load
标题为“client:load”的部分- 优先级: 高
- 适用于: 需要尽快变得可交互的、立即可见的 UI 元素。
在页面加载时立即加载并激活组件的 JavaScript。
<BuyButton client:load />
client:idle
标题为“client:idle”的部分- 优先级: 中
- 适用于: 不需要立即交互的较低优先级的 UI 元素。
一旦页面完成初始加载并且 requestIdleCallback
事件触发,就加载并激活组件的 JavaScript。如果你在不支持 requestIdleCallback
的浏览器中,则会使用文档的 load
事件。
<ShowHideButton client:idle />
新增于: astro@4.15.0
在激活组件之前等待的最大时间(以毫秒为单位),即使页面尚未完成初始加载。
这允许你为requestIdleCallback()
规范中的 timeout
选项传递一个值。这意味着你可以更有控制地延迟较低优先级 UI 元素的激活,以确保你的元素在指定的时间范围内是可交互的。
<ShowHideButton client:idle={{timeout: 500}} />
client:visible
标题为“client:visible”的部分- 优先级: 低
- 适用于: 位于页面下方(“首屏之下”)的低优先级 UI 元素,或者加载它们资源密集到你希望在用户永远看不到该元素的情况下根本不加载它们。
一旦组件进入用户的视口,就加载并激活组件的 JavaScript。它内部使用 IntersectionObserver
来跟踪可见性。
<HeavyImageCarousel client:visible />
client:visible={{rootMargin}}
标题为“client:visible={{rootMargin}}”的部分
添加于: astro@4.1.0
可以选择将 rootMargin
的值传递给底层的 IntersectionObserver
。当指定 rootMargin
时,组件的 JavaScript 将在组件周围的指定边距(以像素为单位)进入视口时激活,而不是组件本身。
<HeavyImageCarousel client:visible={{rootMargin: "200px"}} />
指定 rootMargin
值可以减少布局偏移(CLS),在较慢的网络连接上为组件激活留出更多时间,并使组件更快地变为可交互,从而增强页面的稳定性和响应性。
client:media
标题为“client:media”的部分- 优先级: 低
- 适用于: 侧边栏切换按钮,或其他可能只在特定屏幕尺寸下可见的元素。
client:media={string}
在满足特定 CSS 媒体查询时加载并激活组件的 JavaScript。
如果组件已经通过 CSS 中的媒体查询来控制显示和隐藏,那么只使用 client:visible
而不将相同的媒体查询传递给指令可能会更容易。
<SidebarToggle client:media="(max-width: 50em)" />
client:only
标题为“client:only”的部分client:only={string}
跳过 HTML 服务端渲染,只在客户端渲染。它的行为类似于 client:load
,即在页面加载时立即加载、渲染并激活组件。
你必须将组件对应的框架作为值传递!因为 Astro 在构建期间/服务端上不运行该组件,所以除非你明确告知,否则 Astro 不知道你的组件使用的是哪个框架。
<SomeReactComponent client:only="react" /><SomePreactComponent client:only="preact" /><SomeSvelteComponent client:only="svelte" /><SomeVueComponent client:only="vue" /><SomeSolidComponent client:only="solid-js" />
显示加载内容
标题为“显示加载内容”的部分对于仅在客户端渲染的组件,也可以在它们加载时显示后备内容。在任何子元素上使用 slot="fallback"
来创建内容,这些内容将仅在你的客户端组件可用之前显示
<ClientComponent client:only="vue"> <div slot="fallback">Loading</div></ClientComponent>
自定义客户端指令
标题为“自定义客户端指令”的部分自 Astro 2.6.0 起,集成也可以添加自定义的 client:*
指令来更改组件应该如何以及何时被激活。
访问 addClientDirective
API 页面,了解有关创建自定义客户端指令的更多信息。
服务端指令
标题为“服务端指令”的部分这些指令控制服务端岛屿组件如何渲染。
server:defer
标题为“server:defer”的部分server:defer
指令将组件转换为服务端岛屿,使其在页面其余部分渲染范围之外按需渲染。
<Avatar server:defer />
脚本和样式指令
标题为“脚本和样式指令”的部分这些指令只能用于 HTML 的 <script>
和 <style>
标签,以控制你的客户端 JavaScript 和 CSS 在页面上的处理方式。
is:global
标题为“is:global”的部分默认情况下,Astro 会自动将 <style>
中的 CSS 规则的作用域限定在组件内。你可以使用 is:global
指令来选择退出此行为。
is:global
使得当组件被包含时,<style>
标签的内容会全局应用于页面。这会禁用 Astro 的 CSS 作用域系统。这相当于用 :global()
包装 <style>
标签内的所有选择器。
你可以在同一个组件中结合使用 <style>
和 <style is:global>
,以创建一些全局样式规则,同时仍然将大部分组件 CSS 的作用域限定在组件内。
<style is:global> body a { color: red; }</style>
is:inline
标题为“is:inline”的部分默认情况下,Astro 会处理、优化和打包它在页面上看到的任何 <script>
和 <style>
标签。你可以使用 is:inline
指令来选择退出此行为。
is:inline
告诉 Astro 在最终的 HTML 输出中按原样保留 <script>
或 <style>
标签。其内容不会被处理、优化或打包。这限制了一些 Astro 功能,比如导入 npm 包或使用像 Sass 这样的编译到 CSS 的语言。
is:inline
指令意味着 <style>
和 <script>
标签:
- 不会被打包到外部文件中。这意味着像
defer
这样控制外部文件加载的属性将没有效果。 - 不会被去重——该元素将按其渲染次数出现多次。
- 其
import
/@import
/url()
引用不会相对于.astro
文件进行解析。 - 将在最终的 HTML 输出中完全按照其编写的位置进行渲染。
- 样式将是全局的,而不是限定在组件作用域内。
当在 <script>
或 <style>
标签上使用除 src
之外的任何属性时,is:inline
指令是隐式的。唯一的例外是在 <style>
标签上使用 define:vars
指令,它不会自动暗示 is:inline
。
<style is:inline> /* inline: relative & npm package imports are not supported. */ @import '/assets/some-public-styles.css'; span { color: green; }</style>
<script is:inline> /* inline: relative & npm package imports are not supported. */ console.log('I am inlined right here in the final output HTML.');</script>
define:vars
标题为“define:vars”的部分define:vars={...}
可以将组件 frontmatter 中的服务端变量传递给客户端的 <script>
或 <style>
标签。支持任何可 JSON 序列化的 frontmatter 变量,包括通过 Astro.props
传递给组件的 props
。值会通过 JSON.stringify()
进行序列化。
---const foregroundColor = "rgb(221 243 228)";const backgroundColor = "rgb(24 121 78)";const message = "Astro is awesome!";---<style define:vars={{ textColor: foregroundColor, backgroundColor }}> h1 { background-color: var(--backgroundColor); color: var(--textColor); }</style>
<script define:vars={{ message }}> alert(message);</script>
在 <script>
标签上使用 define:vars
意味着隐式使用了 is:inline
指令,这表示你的脚本将不会被打包,而是会直接内联到 HTML 中。
这是因为当 Astro 打包脚本时,即使你在一个页面上多次包含含有该脚本的组件,它也只会包含并运行该脚本一次。define:vars
要求脚本为每组值重新运行,因此 Astro 会创建一个内联脚本。
对于脚本,请尝试手动将变量传递给脚本。
高级指令
标题为“高级指令”的部分is:raw
标题为“is:raw”的部分is:raw
指示 Astro 编译器将该元素的任何子元素视为文本。这意味着所有特殊的 Astro 模板语法都将在该组件内部被忽略。
例如,如果你有一个将一些文本转换为 HTML 的自定义 Katex 组件,你可以让用户这样做:
---import Katex from '../components/Katex.astro';---<Katex is:raw>Some conflicting {syntax} here</Katex>