Astro 组件使用 .astro 文件扩展名,具有独特的语法结构,结合了服务端代码和客户端模板。
组件结构:
astro--- // 1. 前置脚本(Frontmatter) // 在这里编写服务端代码 const title = "我的博客文章"; const date = new Date().toLocaleDateString(); // 可以导入其他组件 import Card from './Card.astro'; // 可以执行异步操作 const posts = await fetch('/api/posts').then(r => r.json()); --- <!-- 2. 模板区域 --> <!-- 在这里编写 HTML/JSX --> <h1>{title}</h1> <p>发布于 {date}</p> <div class="posts"> {posts.map(post => ( <Card title={post.title} /> ))} </div> <style> /* 3. 样式作用域 */ h1 { color: #333; } </style>
三个主要部分:
-
前置脚本(Frontmatter):
- 使用
---分隔符包裹 - 在构建时执行,不会发送到浏览器
- 可以使用 JavaScript/TypeScript
- 支持导入、异步操作、数据处理
- 使用
-
模板区域:
- 类似 HTML 的语法
- 支持表达式插值
{variable} - 支持条件渲染
{condition && <Component />} - 支持列表渲染
{items.map(item => <Item />)}
-
样式作用域:
- 使用
<style>标签 - 默认是作用域样式(scoped)
- 不会影响其他组件
- 可以使用
:global()选择器定义全局样式
- 使用
Props 传递:
astro--- // 子组件 Card.astro const { title, description } = Astro.props; --- <div class="card"> <h2>{title}</h2> <p>{description}</p> </div> <style> .card { border: 1px solid #ddd; padding: 1rem; } </style>
使用子组件:
astro--- import Card from './Card.astro'; --- <Card title="文章标题" description="文章描述" />
插槽(Slots):
astro--- // Layout.astro const { title } = Astro.props; --- <html> <head> <title>{title}</title> </head> <body> <header> <slot name="header" /> </header> <main> <slot /> <!-- 默认插槽 --> </main> <footer> <slot name="footer" /> </footer> </body> </html>
使用布局:
astro--- import Layout from './Layout.astro'; --- <Layout title="我的页面"> <slot slot="header"> <h1>页面标题</h1> </slot> <p>主要内容</p> <slot slot="footer"> <p>页脚信息</p> </slot> </Layout>
TypeScript 支持:
astro--- interface Props { title: string; count?: number; } const { title, count = 0 } = Astro.props satisfies Props; --- <h1>{title}</h1> <p>数量: {count}</p>
注意事项:
- 前置脚本中的代码不会在浏览器中执行
- 模板中的表达式在构建时求值
- 样式默认是作用域的,不会泄漏
- 组件默认是静态的,需要交互时使用
client:*指令 - 可以在组件中使用任何前端框架的组件
Astro 组件语法简洁而强大,提供了优秀的开发体验和性能表现。