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