name: svelte description: 使用内置响应式、状态管理、SSR/SSG和现代Web模式进行Svelte和SvelteKit开发。 allowed-tools: Read, Write, Edit, Bash, Glob, Grep
Svelte技能
为使用Svelte和SvelteKit构建应用程序提供专家级协助。
能力
- 创建具有响应式声明的Svelte组件
- 实现Svelte状态管理存储
- 配置SvelteKit的SSR/SSG/SPA
- 构建API路由和表单操作
- 设置数据获取的加载函数
- 实现过渡和动画效果
使用场景
在以下情况下调用此技能:
- 构建Svelte/SvelteKit应用程序
- 创建响应式组件
- 实现服务器端渲染
- 设置表单处理操作
- 配置部署
输入参数
| 参数 | 类型 | 必填 | 描述 |
|---|---|---|---|
| componentName | string | 是 | 组件名称 |
| sveltekit | boolean | 否 | 使用SvelteKit(默认:true) |
| typescript | boolean | 否 | 使用TypeScript(默认:true) |
| ssr | boolean | 否 | 启用SSR(默认:true) |
组件模式
基础组件
<!-- src/lib/components/UserCard.svelte -->
<script lang="ts">
interface User {
id: string;
name: string;
email: string;
avatar?: string;
}
export let user: User;
export let editable = false;
let isEditing = false;
let editedName = user.name;
// 响应式声明
$: initials = user.name
.split(' ')
.map(n => n[0])
.join('')
.toUpperCase();
function save() {
user = { ...user, name: editedName };
isEditing = false;
}
</script>
<div class="user-card">
<div class="avatar">
{#if user.avatar}
<img src={user.avatar} alt={user.name} />
{:else}
<span class="initials">{initials}</span>
{/if}
</div>
<div class="info">
{#if isEditing}
<input bind:value={editedName} on:keydown={(e) => e.key === 'Enter' && save()} />
<button on:click={save}>保存</button>
<button on:click={() => isEditing = false}>取消</button>
{:else}
<h2>{user.name}</h2>
<p>{user.email}</p>
{#if editable}
<button on:click={() => { editedName = user.name; isEditing = true; }}>
编辑
</button>
{/if}
{/if}
</div>
</div>
<style>
.user-card {
display: flex;
gap: 1rem;
padding: 1rem;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
}
.avatar {
width: 64px;
height: 64px;
border-radius: 50%;
overflow: hidden;
}
.initials {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
background: #e5e7eb;
font-weight: bold;
}
</style>
Svelte状态管理
// src/lib/stores/user.ts
import { writable, derived, readable } from 'svelte/store';
interface User {
id: string;
name: string;
email: string;
}
// 可写存储
function createUserStore() {
const { subscribe, set, update } = writable<User | null>(null);
return {
subscribe,
login: async (email: string, password: string) => {
const response = await fetch('/api/auth/login', {
method: 'POST',
body: JSON.stringify({ email, password }),
});
const user = await response.json();
set(user);
},
logout: () => set(null),
updateProfile: (data: Partial<User>) =>
update(user => user ? { ...user, ...data } : null),
};
}
export const user = createUserStore();
// 派生存储
export const isAuthenticated = derived(user, $user => !!$user);
// 只读存储(外部数据)
export const time = readable(new Date(), (set) => {
const interval = setInterval(() => set(new Date()), 1000);
return () => clearInterval(interval);
});
SvelteKit页面与加载函数
// src/routes/users/+page.server.ts
import type { PageServerLoad, Actions } from './$types';
import { fail, redirect } from '@sveltejs/kit';
import { db } from '$lib/server/db';
export const load: PageServerLoad = async ({ locals }) => {
if (!locals.user) {
throw redirect(302, '/login');
}
const users = await db.user.findMany();
return {
users,
};
};
export const actions: Actions = {
create: async ({ request }) => {
const data = await request.formData();
const name = data.get('name') as string;
const email = data.get('email') as string;
if (!name || !email) {
return fail(400, { error: '姓名和邮箱必填' });
}
const user = await db.user.create({
data: { name, email },
});
return { success: true, user };
},
delete: async ({ request }) => {
const data = await request.formData();
const id = data.get('id') as string;
await db.user.delete({ where: { id } });
return { success: true };
},
};
<!-- src/routes/users/+page.svelte -->
<script lang="ts">
import type { PageData, ActionData } from './$types';
import { enhance } from '$app/forms';
export let data: PageData;
export let form: ActionData;
</script>
<h1>用户管理</h1>
{#if form?.error}
<p class="error">{form.error}</p>
{/if}
<form method="POST" action="?/create" use:enhance>
<input name="name" placeholder="姓名" required />
<input name="email" type="email" placeholder="邮箱" required />
<button type="submit">添加用户</button>
</form>
<ul>
{#each data.users as user (user.id)}
<li>
{user.name} - {user.email}
<form method="POST" action="?/delete" use:enhance>
<input type="hidden" name="id" value={user.id} />
<button type="submit">删除</button>
</form>
</li>
{/each}
</ul>
API路由
// src/routes/api/users/+server.ts
import { json, error } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { db } from '$lib/server/db';
export const GET: RequestHandler = async ({ url }) => {
const search = url.searchParams.get('search');
const users = await db.user.findMany({
where: search ? { name: { contains: search } } : undefined,
});
return json(users);
};
export const POST: RequestHandler = async ({ request }) => {
const body = await request.json();
if (!body.name || !body.email) {
throw error(400, '姓名和邮箱必填');
}
const user = await db.user.create({
data: body,
});
return json(user, { status: 201 });
};
过渡与动画
<script>
import { fade, fly, slide } from 'svelte/transition';
import { flip } from 'svelte/animate';
let items = [];
let showModal = false;
</script>
{#if showModal}
<div class="modal" transition:fade={{ duration: 200 }}>
<div class="content" in:fly={{ y: -50, duration: 300 }}>
模态框内容
</div>
</div>
{/if}
<ul>
{#each items as item (item.id)}
<li
animate:flip={{ duration: 300 }}
in:slide={{ duration: 200 }}
out:fade={{ duration: 100 }}
>
{item.name}
</li>
{/each}
</ul>
最佳实践
- 使用响应式声明($:)处理派生值
- 利用SvelteKit的加载函数获取数据
- 使用表单操作进行数据变更
- 保持状态管理简单专注
- 使用TypeScript确保类型安全
目标流程
- svelte-application-development
- sveltekit-full-stack
- jamstack-development
- frontend-architecture