协作头脑风暴
brainstorming
在实现前澄清需求、探索设计选择,并形成清晰的开发方向。
svelte【开发与工程】You are an expert in Svelte 5 and SvelteKit 2. You help developers build web applications using runes ($state, $derived, $effect, $props, $bindable, $inspect), snippets, stores, transitions, and actions — compiling to minimal vanilla JavaScript with no virtual DOM. Use when building Svelte apps, migrating from Svelte 4, or working with SvelteKit.
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Svelte shifts work from runtime to compile time, producing minimal vanilla JavaScript with no virtual DOM. Svelte 5 introduces runes — explicit reactivity primitives that replace $: declarations and stores. SvelteKit 2 provides SSR, routing, and deployment adapters.
$state — reactive state (deep by default):
<script lang="ts">
let count = $state(0);
let user = $state({ name: "Alice", age: 30 });
user.age++; // deep reactivity — triggers updates
</script>
$state.raw — shallow reactive (must reassign to trigger):
<script>
let items = $state.raw([1, 2, 3]);
items = [...items, 4]; // must reassign
</script>
$state.snapshot — plain non-reactive copy:
<script>
let form = $state({ name: "", email: "" });
const data = $state.snapshot(form); // plain object for API calls
</script>
$derived and $derived.by — computed values:
<script>
let price = $state(100);
let quantity = $state(3);
let total = $derived(price * quantity);
let summary = $derived.by(() => {
const t = items.reduce((sum, i) => sum + i.price, 0);
return { total: t, count: items.length, avg: t / items.length };
});
</script>
$effect — side effects with cleanup:
<script>
let query = $state("");
$effect(() => {
if (!query) return;
const controller = new AbortController();
fetch(`/api/search?q=${query}`, { signal: controller.signal })
.then(r => r.json()).then(data => { results = data; });
return () => controller.abort();
});
</script>
$props — component props:
<script>
let { label, variant = "primary", onclick, class: className = "", ...rest } = $props();
</script>
<button class="btn btn-{variant} {className}" {onclick} {...rest}>{label}</button>
$bindable — two-way binding:
<!-- Input.svelte -->
<script>
let { value = $bindable(""), placeholder = "" } = $props();
</script>
<input bind:value {placeholder} />
$inspect — debug reactive values (dev only):
<script>
$inspect(count, doubled);
$inspect(count).with((type, value) => console.log(`[${type}]`, value));
</script>
Svelte 5 replaces slots with typed, reusable markup fragments:
<!-- List.svelte -->
<script>
let { items, row, children } = $props();
</script>
<ul>
{#each items as item}
<li>{@render row(item)}</li>
{/each}
</ul>
{@render children?.()}
<!-- Parent.svelte -->
<List {items}>
{#snippet row(item)}
<strong>{item.name}</strong> — {item.description}
{/snippet}
</List>
// stores/cart.ts — Writable store (Svelte 4 style, still works)
import { writable, derived } from "svelte/store";
export const cart = writable<CartItem[]>([]);
export const cartTotal = derived(cart, ($cart) =>
$cart.reduce((sum, item) => sum + item.price * item.quantity, 0)
);
Svelte 5 alternative — $state in .svelte.ts modules:
// state/counter.svelte.ts
let count = $state(0);
let doubled = $derived(count * 2);
export function getCounter() {
return {
get count() { return count; },
get doubled() { return doubled; },
increment() { count++; },
};
}
<script>
import { fade, fly, slide } from "svelte/transition";
import { flip } from "svelte/animate";
let items = $state(["Apple", "Banana"]);
</script>
{#each items as item (item)}
<div animate:flip={{ duration: 300 }} transition:fade>{item}</div>
{/each}
| Svelte 4 | Svelte 5 |
|---|---|
let count = 0 | let count = $state(0) |
$: doubled = count * 2 | let doubled = $derived(count * 2) |
$: { sideEffect() } | $effect(() => { sideEffect() }) |
export let prop | let { prop } = $props() |
<slot /> | {@render children()} |
<slot name="header" /> | {@render header?.()} |
| Svelte stores | $state in .svelte.ts files |
<!-- +page.svelte -->
<script>
let { data } = $props(); // from +page.ts load function
</script>
<h1>{data.title}</h1>
npx sv create my-app # SvelteKit project
npm create vite@latest -- --template svelte-ts # standalone Svelte
<!-- CartSummary.svelte -->
<script lang="ts">
import { cart, cartTotal, removeFromCart } from "$lib/stores/cart";
</script>
<div class="cart">
{#each $cart as item (item.id)}
<div>{item.name} x {item.quantity} — ${(item.price * item.quantity).toFixed(2)}
<button onclick={() => removeFromCart(item.id)}>Remove</button>
</div>
{/each}
<p>Total: ${$cartTotal.toFixed(2)}</p>
</div>
<script>
let userId = $state(1);
let user = $state(null);
let loading = $state(false);
$effect(() => {
loading = true;
fetch(`/api/users/${userId}`)
.then(r => r.json())
.then(data => { user = data; loading = false; });
});
</script>
{#if loading}<p>Loading...</p>
{:else if user}<p>{user.name}</p>{/if}
$state(), $derived(), $effect() in Svelte 5; cleaner than Svelte 4's $: syntax<style> is component-scoped; no CSS modules needed$state in .svelte.ts for new code; writable/derived stores still worktransition:fade, transition:fly; no animation library needed<script lang="ts"> for type-safe componentsuse:action for reusable DOM behavior (click-outside, tooltip)