Skip to content

组件

Astro 组件 是任何 Astro 项目的基本构建块。 它们是纯 HTML 模板组件,没有客户端运行时。 你可以通过文件扩展名来识别 Astro 组件: .astro

Astro components are the basic building blocks of any Astro project. They are HTML-only templating components with no client-side runtime. You can spot an Astro component by its file extension: .astro.

Astro 组件非常灵活。 通常,Astro 组件会包含一些 页面上可重用的 UI,例如标题或配置文件卡。 有时,Astro 组件可能包含较小的 HTML 片段,例如使 SEO 易于使用的常见 <meta> 标签的集合。 Astro 组件甚至可以包含整个页面布局。

Astro components are extremely flexible. Often, an Astro component will contain some reusable UI on the page, like a header or a profile card. At other times, an Astro component may contain a smaller snippet of HTML, like a collection of common <meta> tags that make SEO easy to work with. Astro components can even contain an entire page layout.

关于 Astro 组件,最重要的是要了解它们 不要在客户端渲染。 它们在构建时或按需使用 服务器端渲染(SSR) 渲染为 HTML。 你可以在组件 frontmatter 中包含 JavaScript 代码,所有这些代码都将从发送到用户浏览器的最终页面中删除。 结果是网站速度更快,默认情况下添加的 JavaScript 占用量为零。

The most important thing to know about Astro components is that they don’t render on the client. They render to HTML either at build-time or on-demand using server-side rendering (SSR). You can include JavaScript code inside of your component frontmatter, and all of it will be stripped from the final page sent to your users’ browsers. The result is a faster site, with zero JavaScript footprint added by default.

当你的 Astro 组件确实需要客户端交互时,你可以添加 标准 HTML <script> 标签UI 框架组件

When your Astro component does need client-side interactivity, you can add standard HTML <script> tags or UI Framework components.

Astro 组件由两个主要部分组成: 组件脚本组件模板。 每个部分执行不同的工作,但它们共同提供了一个既易于使用又具有足够表现力的框架,足以处理你可能想要构建的任何内容。

An Astro component is made up of two main parts: the Component Script and the Component Template. Each part performs a different job, but together they provide a framework that is both easy to use and expressive enough to handle whatever you might want to build.

src/components/EmptyComponent.astro
---
// Component Script (JavaScript)
---
<!-- Component Template (HTML + JS Expressions) -->

Astro 使用代码围栏 (---) 来识别 Astro 组件中的组件脚本。 如果你以前编写过 Markdown,你可能已经熟悉称为 frontmatter 的类似概念。 Astro 组件脚本的想法直接受到这个概念的启发。

Astro uses a code fence (---) to identify the component script in your Astro component. If you’ve ever written Markdown before, you may already be familiar with a similar concept called frontmatter. Astro’s idea of a component script was directly inspired by this concept.

你可以使用组件脚本编写渲染模板所需的任何 JavaScript 代码。 这可以包括:

You can use the component script to write any JavaScript code that you need to render your template. This can include:

  • 导入其他 Astro 组件
  • 导入其他框架组件,例如 React
  • 导入数据,例如 JSON 文件
  • 从 API 或数据库获取内容
  • 创建你将在模板中引用的变量
src/components/MyComponent.astro
---
import SomeAstroComponent from '../components/SomeAstroComponent.astro';
import SomeReactComponent from '../components/SomeReactComponent.jsx';
import someData from '../data/pokemon.json';
// Access passed-in component props, like `<X title="Hello, World" />`
const {title} = Astro.props;
// Fetch external data, even from a private API or database
const data = await fetch('SOME_SECRET_API_URL/users').then(r => r.json());
---
<!-- Your template here! -->

代码围栏旨在保证你在其中编写的 JavaScript 是 “围起来。” 的,它不会转义到你的前端应用中,或落入你的用户手中。 你可以在这里安全地编写昂贵或敏感的代码(例如对你的私有数据库的调用),而不必担心它最终会出现在用户的浏览器中。

The code fence is designed to guarantee that the JavaScript that you write in it is “fenced in.” It won’t escape into your frontend application, or fall into your user’s hands. You can safely write code here that is expensive or sensitive (like a call to your private database) without worrying about it ever ending up in your user’s browser.

:::tip 提示 你甚至可以在组件脚本中编写 TypeScript! :::

组件模板位于代码围栏下方,决定组件的 HTML 输出。

The component template is below the code fence and determines the HTML output of your component.

如果你在此处编写纯 HTML,你的组件将在导入和使用的任何 Astro 页面中渲染该 HTML。

If you write plain HTML here, your component will render that HTML in any Astro page it is imported and used.

但是,Astro 的组件模板语法 还支持 JavaScript 表达式、Astro <style><script> 标签、导入组件特别 Astro 指令。 组件脚本中定义的数据和值可以在组件模板中使用来生成动态创建的 HTML。

However, Astro’s component template syntax also supports JavaScript expressions, Astro <style> and <script> tags, imported components, and special Astro directives. Data and values defined in the component script can be used in the component template to produce dynamically-created HTML.

src/components/MyFavoritePokemon.astro
---
// Your component script here!
import Banner from '../components/Banner.astro';
import ReactPokemonComponent from '../components/ReactPokemonComponent.jsx';
const myFavoritePokemon = [/* ... */];
const { title } = Astro.props;
---
<!-- HTML comments supported! -->
{/* JS comment syntax is also valid! */}
<Banner />
<h1>Hello, world!</h1>
<!-- Use props and other variables from the component script: -->
<p>
{title}
</p>
<!-- Include other UI framework components with a `client:` directive to hydrate: -->
<ReactPokemonComponent client:visible />
<!-- Mix HTML with JavaScript expressions, similar to JSX: -->
<ul>
{myFavoritePokemon.map((data) => <li>{data.name}</li>)}
</ul>
<!-- Use a template directive to build class names from multiple strings or even objects! -->
<p class:list={["add", "dynamic", {classNames: true}]} />

组件设计为 reusablecomposable。 你可以使用其他组件内部的组件来构建越来越高级的 UI。 例如,Button 组件可用于创建 ButtonGroup 组件:

Components are designed to be reusable and composable. You can use components inside of other components to build more and more advanced UI. For example, a Button component could be used to create a ButtonGroup component:

src/components/ButtonGroup.astro
---
import Button from './Button.astro';
---
<div>
<Button title="Button 1" />
<Button title="Button 2" />
<Button title="Button 3" />
</div>

Astro 组件可以定义和接受 props。 然后,这些 props 可用于组件模板来渲染 HTML。 属性可在 frontmatter 脚本中的 Astro.props 全局上使用。

An Astro component can define and accept props. These props then become available to the component template for rendering HTML. Props are available on the Astro.props global in your frontmatter script.

以下是接收 greeting prop 和 name prop 的组件示例。 请注意,要接收的 props 是从全局 Astro.props 对象中解构的。

Here is an example of a component that receives a greeting prop and a name prop. Notice that the props to be received are destructured from the global Astro.props object.

src/components/GreetingHeadline.astro
---
// Usage: <GreetingHeadline greeting="Howdy" name="Partner" />
const { greeting, name } = Astro.props;
---
<h2>{greeting}, {name}!</h2>

该组件在其他 Astro 组件、布局或页面中导入和渲染时,可以将这些 props 作为属性传递:

This component, when imported and rendered in other Astro components, layouts or pages, can pass these props as attributes:

src/components/GreetingCard.astro
---
import GreetingHeadline from './GreetingHeadline.astro';
const name = "Astro"
---
<h1>Greeting Card</h1>
<GreetingHeadline greeting="Hi" name={name} />
<p>I hope you have a wonderful day!
</p>

你还可以使用带有 Props 类型接口的 TypeScript 定义你的 props。 Astro 将自动在你的 frontmatter 中选取 Props 接口并给出类型警告/错误。 当从 Astro.props 解构时,这些属性也可以被赋予默认值。

You can also define your props with TypeScript with a Props type interface. Astro will automatically pick up the Props interface in your frontmatter and give type warnings/errors. These props can also be given default values when destructured from Astro.props.

src/components/GreetingHeadline.astro
---
interface Props {
name: string;
greeting?: string;
}
const { greeting = "Hello", name } = Astro.props;
---
<h2>{greeting}, {name}!</h2>

当没有提供组件属性时,可以给组件属性指定默认值以供使用。

Component props can be given default values to use when none are provided.

src/components/GreetingHeadline.astro
---
const { greeting = "Hello", name = "Astronaut" } = Astro.props;
---
<h2>{greeting}, {name}!</h2>

<slot /> 元素是外部 HTML 内容的占位符,允许你将其他文件中的子元素(或 “slot”)注入到组件模板中。

The <slot /> element is a placeholder for external HTML content, allowing you to inject (or “slot”) child elements from other files into your component template.

默认情况下,传递给组件的所有子元素都将在其 <slot /> 中渲染

By default, all child elements passed to a component will be rendered in its <slot />

:::note 注意 与 props 不同的是,props 是传递给 Astro 组件的属性,可在整个组件中使用 Astro.props 使用,而 slot 会在编写子 HTML 元素时渲染它们。 :::

src/components/Wrapper.astro
---
import Header from './Header.astro';
import Logo from './Logo.astro';
import Footer from './Footer.astro';
const { title } = Astro.props
---
<div id="content-wrapper">
<Header />
<Logo />
<h1>{title}</h1>
<slot /> <!-- children will go here -->
<Footer />
</div>
src/pages/fred.astro
---
import Wrapper from '../components/Wrapper.astro';
---
<Wrapper title="Fred's Page">
<h2>All about Fred</h2>
<p>
Here is some stuff about Fred.
</p>
</Wrapper>

该模式是 Astro 布局组件 的基础: 整个 HTML 内容页面可以是 “wrapped” 和 <SomeLayoutComponent></SomeLayoutComponent> 标签,并发送到组件以在定义的公共页面元素内部进行渲染。

This pattern is the basis of an Astro layout component: an entire page of HTML content can be “wrapped” with <SomeLayoutComponent></SomeLayoutComponent> tags and sent to the component to render inside of common page elements defined there.

Astro 组件也可以有命名槽。 这允许你仅将具有相应插槽名称的 HTML 元素传递到插槽的位置。

An Astro component can also have named slots. This allows you to pass only HTML elements with the corresponding slot name into a slot’s location.

插槽使用 name 属性命名:

Slots are named using the name attribute:

src/components/Wrapper.astro
---
import Header from './Header.astro';
import Logo from './Logo.astro';
import Footer from './Footer.astro';
const { title } = Astro.props
---
<div id="content-wrapper">
<Header />
<slot name="after-header"/> <!-- children with the `slot="after-header"` attribute will go here -->
<Logo />
<h1>{title}</h1>
<slot /> <!-- children without a `slot`, or with `slot="default"` attribute will go here -->
<Footer />
<slot name="after-footer"/> <!-- children with the `slot="after-footer"` attribute will go here -->
</div>

要将 HTML 内容注入特定槽,请在任何子元素上使用 slot 属性来指定槽的名称。 该组件的所有其他子元素都将被注入到默认(未命名)的 <slot /> 中。

To inject HTML content into a particular slot, use the slot attribute on any child element to specify the name of the slot. All other child elements of the component will be injected into the default (unnamed) <slot />.

src/pages/fred.astro
---
import Wrapper from '../components/Wrapper.astro';
---
<Wrapper title="Fred's Page">
<img src="https://my.photo/fred.jpg" slot="after-header">
<h2>All about Fred</h2>
<p>
Here is some stuff about Fred.
</p>
<p slot="after-footer">
Copyright 2022
</p>
</Wrapper>

在要传递到组件中匹配的 <slot name="my-slot" /> 占位符的子元素上使用 slot="my-slot" 属性。

Use a slot="my-slot" attribute on the child element that you want to pass through to a matching <slot name="my-slot" /> placeholder in your component.

请注意,命名槽必须是组件的直接子级。 你不能通过嵌套元素传递命名槽。

Note that named slots must be an immediate child of the component. You cannot pass named slots through nested elements.

:::tip 提示 命名槽也可以传递给 UI 框架组件! :::

:::note 注意 astro 插槽名称无法动态生成,例如在地图函数中。 如果 UI 框架组件内需要此功能,则最好在框架本身内生成这些动态槽。 :::

插槽也可以渲染 后备内容。 当没有匹配的子元素传递到槽时,<slot /> 元素将渲染其自己的占位符子元素。

Slots can also render fallback content. When there are no matching children passed to a slot, a <slot /> element will render its own placeholder children.

src/components/Wrapper.astro
---
import Header from './Header.astro';
import Logo from './Logo.astro';
import Footer from './Footer.astro';
const { title } = Astro.props
---
<div id="content-wrapper">
<Header />
<Logo />
<h1>{title}</h1>
<slot>
<p>
This is my fallback content, if there is no child passed into slot
</p>
</slot>
<Footer />
</div>

插槽可以转移到其他组件。 例如,创建嵌套布局时:

Slots can be transferred to other components. For example, when creating nested layouts:

src/layouts/BaseLayout.astro
---
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<slot name="head"/>
</head>
<body>
<slot />
</body>
</html>
src/layouts/HomeLayout.astro
---
import BaseLayout from "./BaseLayout.astro";
---
<BaseLayout>
<slot name="head" slot="head"/>
<slot />
</BaseLayout>

:::note 注意 可以使用 <slot /> 标签上的 nameslot 属性将命名槽转移到另一个组件:::

现在,传递给 HomeLayout 的默认槽和 head 槽将被转移到 BaseLayout 父槽

Now, the default and head slots passed to HomeLayout will be transferred to the BaseLayout parent

src/pages/index.astro
---
import HomeLayout from "../layouts/HomeLayout.astro";
---
<HomeLayout>
<title slot="head">Astro</title>
<h1>Astro</h1>
</HomeLayout>

Astro 支持导入和使用 .html 文件作为组件,或将这些文件作为页面放置在 src/pages/ 子目录中。 如果你要重用不使用框架构建的现有站点中的代码,或者想要确保组件没有动态功能,则可能需要使用 HTML 组件。

Astro supports importing and using .html files as components or placing these files within the src/pages/ subdirectory as pages. You may want to use HTML components if you’re reusing code from an existing site built without a framework, or if you want to ensure that your component has no dynamic features.

HTML 组件必须仅包含有效的 HTML,因此缺少关键的 Astro 组件功能:

  • 它们不支持 frontmatter、服务器端导入或动态表达式。
  • 任何 <script> 标签都不会打包,就像它们具有 is:inline 一样。
  • 他们只能 public/ 文件夹中的参考资源

:::note 注意 HTML 组件内的 <slot /> 元素 的工作方式与 Astro 组件内的工作方式相同。 要改用 HTML Web 组件槽 元素,请将 is:inline 添加到 <slot> 元素中。 :::

📚 了解如何在 Astro 项目中使用 UI 框架组件

📚 Learn about using UI framework components in your Astro project.