UI框架集成 #
一、框架集成概述 #
1.1 为什么需要 UI 框架? #
Astro 默认使用 .astro 组件,但有时需要使用其他框架:
| 场景 | 说明 |
|---|---|
| 交互组件 | 需要复杂状态管理 |
| 现有代码 | 复用已有的 React/Vue 组件 |
| 生态系统 | 使用特定框架的库 |
| 团队熟悉度 | 团队更熟悉某个框架 |
1.2 支持的框架 #
| 框架 | 集成包 |
|---|---|
| React | @astrojs/react |
| Vue | @astrojs/vue |
| Svelte | @astrojs/svelte |
| Solid | @astrojs/solid-js |
| Preact | @astrojs/preact |
| AlpineJS | @astrojs/alpinejs |
| Lit | @astrojs/lit |
二、React 集成 #
2.1 安装配置 #
bash
npm install @astrojs/react react react-dom
javascript
// astro.config.mjs
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
export default defineConfig({
integrations: [react()],
});
2.2 创建 React 组件 #
tsx
// src/components/Counter.tsx
import { useState } from 'react';
interface CounterProps {
initialCount?: number;
}
export default function Counter({ initialCount = 0 }: CounterProps) {
const [count, setCount] = useState(initialCount);
return (
<div className="counter">
<p>Count: {count}</p>
<button onClick={() => setCount(count - 1)}>-</button>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}
2.3 在 Astro 中使用 #
astro
---
// src/pages/index.astro
import Counter from '../components/Counter';
---
<html>
<body>
<h1>React Counter</h1>
<!-- 交互组件需要 client 指令 -->
<Counter client:load />
</body>
</html>
三、Vue 集成 #
3.1 安装配置 #
bash
npm install @astrojs/vue vue
javascript
// astro.config.mjs
import { defineConfig } from 'astro/config';
import vue from '@astrojs/vue';
export default defineConfig({
integrations: [vue()],
});
3.2 创建 Vue 组件 #
vue
<!-- src/components/TodoList.vue -->
<template>
<div class="todo-list">
<input
v-model="newTodo"
@keyup.enter="addTodo"
placeholder="添加任务"
/>
<ul>
<li v-for="todo in todos" :key="todo.id">
<input type="checkbox" v-model="todo.done" />
<span :class="{ done: todo.done }">{{ todo.text }}</span>
<button @click="removeTodo(todo.id)">删除</button>
</li>
</ul>
</div>
</template>
<script setup>
import { ref } from 'vue';
const newTodo = ref('');
const todos = ref([
{ id: 1, text: '学习 Astro', done: false },
]);
function addTodo() {
if (newTodo.value.trim()) {
todos.value.push({
id: Date.now(),
text: newTodo.value,
done: false,
});
newTodo.value = '';
}
}
function removeTodo(id) {
todos.value = todos.value.filter(t => t.id !== id);
}
</script>
<style scoped>
.done {
text-decoration: line-through;
color: #999;
}
</style>
3.3 在 Astro 中使用 #
astro
---
import TodoList from '../components/TodoList.vue';
---
<div>
<h1>Vue Todo List</h1>
<TodoList client:load />
</div>
四、Svelte 集成 #
4.1 安装配置 #
bash
npm install @astrojs/svelte svelte
javascript
// astro.config.mjs
import { defineConfig } from 'astro/config';
import svelte from '@astrojs/svelte';
export default defineConfig({
integrations: [svelte()],
});
4.2 创建 Svelte 组件 #
svelte
<!-- src/components/Toggle.svelte -->
<script>
let isOn = false;
function toggle() {
isOn = !isOn;
}
</script>
<button
class="toggle"
class:on={isOn}
on:click={toggle}
>
{isOn ? 'ON' : 'OFF'}
</button>
<style>
.toggle {
padding: 0.5rem 1rem;
border: 2px solid #ccc;
background: white;
cursor: pointer;
}
.toggle.on {
background: #10b981;
border-color: #10b981;
color: white;
}
</style>
4.3 在 Astro 中使用 #
astro
---
import Toggle from '../components/Toggle.svelte';
---
<div>
<h1>Svelte Toggle</h1>
<Toggle client:visible />
</div>
五、Client 指令 #
5.1 指令列表 #
| 指令 | 说明 |
|---|---|
client:load |
页面加载时立即加载 JS |
client:idle |
浏览器空闲时加载 |
client:visible |
组件可见时加载 |
client:media |
满足媒体查询时加载 |
client:only |
仅在客户端渲染 |
5.2 使用示例 #
astro
---
import Counter from '../components/Counter';
import HeavyChart from '../components/HeavyChart';
import MobileMenu from '../components/MobileMenu';
---
<!-- 立即加载:首屏关键交互 -->
<Counter client:load />
<!-- 空闲加载:非关键交互 -->
<HeavyChart client:idle />
<!-- 可见加载:滚动到视口时 -->
<HeavyChart client:visible />
<!-- 媒体查询:移动端菜单 -->
<MobileMenu client:media="(max-width: 768px)" />
<!-- 仅客户端:依赖浏览器 API -->
<BrowserOnly client:only="react" />
六、混合使用 #
6.1 多框架混用 #
astro
---
import ReactCounter from '../components/ReactCounter';
import VueTodo from '../components/VueTodo.vue';
import SvelteToggle from '../components/SvelteToggle.svelte';
---
<div>
<h1>多框架混合</h1>
<section>
<h2>React Counter</h2>
<ReactCounter client:load />
</section>
<section>
<h2>Vue Todo</h2>
<VueTodo client:visible />
</section>
<section>
<h2>Svelte Toggle</h2>
<SvelteToggle client:visible />
</section>
</div>
6.2 共享状态 #
使用 Nanostores 共享状态:
bash
npm install nanostores @nanostores/react
typescript
// src/stores/counter.ts
import { atom } from 'nanostores';
export const counter = atom(0);
export function increment() {
counter.set(counter.get() + 1);
}
export function decrement() {
counter.set(counter.get() - 1);
}
tsx
// src/components/ReactCounter.tsx
import { useStore } from '@nanostores/react';
import { counter, increment, decrement } from '../stores/counter';
export default function ReactCounter() {
const value = useStore(counter);
return (
<div>
<p>Count: {value}</p>
<button onClick={decrement}>-</button>
<button onClick={increment}>+</button>
</div>
);
}
七、最佳实践 #
7.1 选择合适的指令 #
text
关键交互 → client:load
非关键交互 → client:idle
滚动内容 → client:visible
移动端组件 → client:media
浏览器依赖 → client:only
7.2 最小化 JS #
astro
---
import StaticCard from '../components/StaticCard.astro';
import InteractiveCard from '../components/InteractiveCard';
---
<div>
<!-- 静态内容使用 Astro 组件 -->
<StaticCard title="静态内容" />
<!-- 只有交互部分使用框架组件 -->
<InteractiveCard client:visible />
</div>
八、总结 #
UI 框架集成核心要点:
text
┌─────────────────────────────────────────────────────┐
│ UI 框架集成要点 │
├─────────────────────────────────────────────────────┤
│ │
│ 🔌 集成安装 安装对应的集成包 │
│ │
│ 📦 组件创建 按框架规范创建组件 │
│ │
│ 🚀 Client指令 控制组件加载时机 │
│ │
│ 🔀 混合使用 多框架可同时使用 │
│ │
│ 📊 状态共享 使用 Nanostores │
│ │
└─────────────────────────────────────────────────────┘
下一步,让我们学习 岛屿架构,深入理解 Astro 的核心架构!
最后更新:2026-03-28