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.

¥Component Structure

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) -->

¥The Component Script

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.

¥The Component Template

组件模板位于代码围栏下方,决定组件的 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’s component template syntax also supports JavaScript expressions, Astro <style> and <script> tags, imported components, and special Astro directives。组件脚本中定义的数据和值可以在组件模板中使用来生成动态创建的 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}]} />

¥Component-based design

组件设计为可重复使用和可组合。你可以使用其他组件内部的组件来构建越来越高级的 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>

¥Component Props

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>

¥Slots

<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 />.

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 内容可以用 <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.

¥Named Slots

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>

要将多个 HTML 元素传递到组件的 <slot/> 占位符中而不使用封装 <div>,请在 Astro 的 <Fragment/> 组件 上使用 slot="" 属性:

¥To pass multiple HTML elements into a component’s <slot/> placeholder without a wrapping <div>, use the slot="" attribute on Astro’s <Fragment/> component:

src/components/CustomTable.astro
---
// Create a custom table with named slot placeholders for head and body content
---
<table class="bg-white">
<thead class="sticky top-0 bg-white"><slot name="header" /></thead>
<tbody class="[&_tr:nth-child(odd)]:bg-gray-100"><slot name="body" /></tbody>
</table>

使用 slot="" 属性注入多行和多列 HTML 内容以指定 "header""body" 内容。也可以设置单个 HTML 元素的样式:

¥Inject multiple rows and columns of HTML content using a slot="" attribute to specify the "header" and "body" content. Individual HTML elements can also be styled:

src/components/StockTable.astro
---
import CustomTable from './CustomTable.astro';
---
<CustomTable>
<Fragment slot="header"> <!-- pass table header -->
<tr><th>Product name</th><th>Stock units</th></tr>
</Fragment>
<Fragment slot="body"> <!-- pass table body -->
<tr><td>Flip-flops</td><td>64</td></tr>
<tr><td>Boots</td><td>32</td></tr>
<tr><td>Sneakers</td><td class="text-red-500">0</td></tr>
</Fragment>
</CustomTable>

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

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

¥Fallback Content for Slots

Slots 还可以渲染后备内容。当没有匹配的子元素传递到槽时,<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>

仅在没有匹配的元素将 slot=“name” 属性传递给命名插槽时才会显示后备内容。

¥Fallback content will only be displayed when there are no matching elements with the slot=“name” attribute being passed in to a named slot.

当存在插槽元素但没有要传递的内容时,Astro 会传递一个空插槽。传递空插槽时,不能将后备内容用作默认值。仅在找不到插槽元素时才显示后备内容。

¥Astro will pass an empty slot when a slot element exists but has no content to pass. Fallback content cannot be used as a default when an empty slot is passed. Fallback content is only displayed when no slot element can be found.

¥Transferring slots

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

¥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>

现在,传递给 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>

¥HTML Components

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 组件功能:

¥HTML components must contain only valid HTML, and therefore lack key Astro component features:

  • 它们不支持 frontmatter、服务器端导入或动态表达式。

  • 任何 <script> 标签都不会打包,就像它们具有 is:inline 一样。

  • 他们只能 public/ 文件夹中的参考资源

¥Next Steps

Read more about using UI framework components in your Astro project.
Astro 中文网 - 粤ICP备13048890号