第一个Svelte应用 #
一、创建项目 #
1.1 初始化项目 #
bash
npm create vite@latest my-first-svelte -- --template svelte
cd my-first-svelte
npm install
npm run dev
1.2 项目结构 #
text
my-first-svelte/
├── src/
│ ├── lib/
│ │ └── Counter.svelte
│ ├── App.svelte
│ ├── app.css
│ └── main.js
├── index.html
└── package.json
二、理解组件 #
2.1 App.svelte 结构 #
打开 src/App.svelte,你会看到 Svelte 组件的基本结构:
svelte
<script>
let count = 0;
</script>
<main>
<h1>Hello Svelte!</h1>
<p>Count: {count}</p>
</main>
<style>
main {
text-align: center;
padding: 2rem;
}
h1 {
color: #ff3e00;
}
</style>
2.2 组件三要素 #
text
┌─────────────────────────────────────────┐
│ Svelte 组件 │
├─────────────────────────────────────────┤
│ <script> JavaScript 逻辑 │
│ ... │
│ </script> │
├─────────────────────────────────────────┤
│ HTML 模板 │
│ <div>...</div> │
├─────────────────────────────────────────┤
│ <style> CSS 样式(自动作用域) │
│ ... │
│ </style> │
└─────────────────────────────────────────┘
三、构建计数器应用 #
3.1 基础计数器 #
修改 src/App.svelte:
svelte
<script>
let count = 0;
function increment() {
count += 1;
}
function decrement() {
count -= 1;
}
function reset() {
count = 0;
}
</script>
<main>
<h1>计数器</h1>
<p class="count">{count}</p>
<div class="buttons">
<button on:click={decrement}>-</button>
<button on:click={reset}>重置</button>
<button on:click={increment}>+</button>
</div>
</main>
<style>
main {
text-align: center;
padding: 2rem;
}
h1 {
color: #333;
margin-bottom: 1rem;
}
.count {
font-size: 4rem;
font-weight: bold;
color: #ff3e00;
margin: 1rem 0;
}
.buttons {
display: flex;
gap: 1rem;
justify-content: center;
}
button {
padding: 0.5rem 1.5rem;
font-size: 1.2rem;
border: none;
border-radius: 4px;
cursor: pointer;
background: #ff3e00;
color: white;
transition: background 0.2s;
}
button:hover {
background: #e63600;
}
</style>
3.2 添加响应式声明 #
svelte
<script>
let count = 0;
$: doubled = count * 2;
$: isPositive = count > 0;
$: isNegative = count < 0;
function increment() {
count += 1;
}
function decrement() {
count -= 1;
}
function reset() {
count = 0;
}
</script>
<main>
<h1>计数器</h1>
<p class="count" class:positive={isPositive} class:negative={isNegative}>
{count}
</p>
<p class="info">双倍值: {doubled}</p>
<div class="buttons">
<button on:click={decrement}>-</button>
<button on:click={reset}>重置</button>
<button on:click={increment}>+</button>
</div>
</main>
<style>
.positive { color: green; }
.negative { color: red; }
.info { color: #666; }
</style>
3.3 Svelte 5 Runes 版本 #
svelte
<script>
let count = $state(0);
let doubled = $derived(count * 2);
let isPositive = $derived(count > 0);
let isNegative = $derived(count < 0);
function increment() {
count += 1;
}
function decrement() {
count -= 1;
}
function reset() {
count = 0;
}
$effect(() => {
document.title = `Count: ${count}`;
});
</script>
<main>
<h1>计数器</h1>
<p class="count" class:positive={isPositive} class:negative={isNegative}>
{count}
</p>
<p class="info">双倍值: {doubled}</p>
<div class="buttons">
<button onclick={decrement}>-</button>
<button onclick={reset}>重置</button>
<button onclick={increment}>+</button>
</div>
</main>
四、添加更多功能 #
4.1 步进值控制 #
svelte
<script>
let count = 0;
let step = 1;
$: doubled = count * 2;
function increment() {
count += step;
}
function decrement() {
count -= step;
}
function reset() {
count = 0;
}
</script>
<main>
<h1>计数器</h1>
<label>
步进值:
<input type="number" bind:value={step} min="1" max="10" />
</label>
<p class="count">{count}</p>
<p class="info">双倍值: {doubled}</p>
<div class="buttons">
<button on:click={decrement}>-{step}</button>
<button on:click={reset}>重置</button>
<button on:click={increment}>+{step}</button>
</div>
</main>
<style>
label {
display: block;
margin-bottom: 1rem;
}
input {
width: 60px;
padding: 0.3rem;
font-size: 1rem;
margin-left: 0.5rem;
}
</style>
4.2 历史记录功能 #
svelte
<script>
let count = 0;
let history = [];
function recordAction(action) {
history = [...history, { action, value: count, time: new Date() }];
}
function increment() {
count += 1;
recordAction('increment');
}
function decrement() {
count -= 1;
recordAction('decrement');
}
function reset() {
count = 0;
recordAction('reset');
}
function clearHistory() {
history = [];
}
</script>
<main>
<h1>计数器</h1>
<p class="count">{count}</p>
<div class="buttons">
<button on:click={decrement}>-</button>
<button on:click={reset}>重置</button>
<button on:click={increment}>+</button>
</div>
{#if history.length > 0}
<div class="history">
<h3>操作历史</h3>
<button on:click={clearHistory}>清除历史</button>
<ul>
{#each history as item}
<li>{item.action}: {item.value} ({item.time.toLocaleTimeString()})</li>
{/each}
</ul>
</div>
{/if}
</main>
五、创建可复用组件 #
5.1 创建 Button 组件 #
src/lib/Button.svelte:
svelte
<script>
let {
type = 'default',
disabled = false,
onclick
} = $props();
</script>
<button
class={`btn btn-${type}`}
{disabled}
{onclick}
>
<slot />
</button>
<style>
.btn {
padding: 0.5rem 1.5rem;
font-size: 1rem;
border: none;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s;
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.btn-default {
background: #ff3e00;
color: white;
}
.btn-default:hover:not(:disabled) {
background: #e63600;
}
.btn-secondary {
background: #666;
color: white;
}
.btn-secondary:hover:not(:disabled) {
background: #555;
}
</style>
5.2 使用 Button 组件 #
svelte
<script>
import Button from './lib/Button.svelte';
let count = 0;
function increment() {
count += 1;
}
function decrement() {
count -= 1;
}
function reset() {
count = 0;
}
</script>
<main>
<h1>计数器</h1>
<p class="count">{count}</p>
<div class="buttons">
<Button onclick={decrement}>-</Button>
<Button type="secondary" onclick={reset}>重置</Button>
<Button onclick={increment}>+</Button>
</div>
</main>
六、完整示例 #
6.1 完整计数器应用 #
svelte
<script>
import Button from './lib/Button.svelte';
let count = $state(0);
let step = $state(1);
let history = $state([]);
let doubled = $derived(count * 2);
let isPositive = $derived(count > 0);
let isNegative = $derived(count < 0);
let isZero = $derived(count === 0);
function recordAction(action) {
history = [...history, {
action,
value: count,
time: new Date()
}];
}
function increment() {
count += step;
recordAction('increment');
}
function decrement() {
count -= step;
recordAction('decrement');
}
function reset() {
count = 0;
recordAction('reset');
}
function clearHistory() {
history = [];
}
$effect(() => {
document.title = `计数器: ${count}`;
});
</script>
<main>
<h1>🔢 计数器应用</h1>
<div class="controls">
<label>
步进值:
<input type="number" bind:value={step} min="1" max="10" />
</label>
</div>
<p
class="count"
class:positive={isPositive}
class:negative={isNegative}
class:zero={isZero}
>
{count}
</p>
<p class="info">双倍值: {doubled}</p>
<div class="buttons">
<Button onclick={decrement}>-{step}</Button>
<Button type="secondary" onclick={reset} disabled={isZero}>重置</Button>
<Button onclick={increment}>+{step}</Button>
</div>
{#if history.length > 0}
<div class="history">
<h3>
操作历史
<Button type="secondary" onclick={clearHistory}>清除</Button>
</h3>
<ul>
{#each history.slice(-5) as item}
<li>
<span class="action">{item.action}</span>
<span class="value">{item.value}</span>
<span class="time">{item.time.toLocaleTimeString()}</span>
</li>
{/each}
</ul>
</div>
{/if}
</main>
<style>
main {
max-width: 400px;
margin: 2rem auto;
padding: 2rem;
text-align: center;
background: #f5f5f5;
border-radius: 8px;
}
h1 {
color: #333;
margin-bottom: 1.5rem;
}
.controls {
margin-bottom: 1rem;
}
label {
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
input {
width: 60px;
padding: 0.3rem;
font-size: 1rem;
border: 1px solid #ccc;
border-radius: 4px;
}
.count {
font-size: 4rem;
font-weight: bold;
margin: 1rem 0;
transition: color 0.3s;
}
.positive { color: #22c55e; }
.negative { color: #ef4444; }
.zero { color: #666; }
.info {
color: #888;
margin-bottom: 1.5rem;
}
.buttons {
display: flex;
gap: 0.5rem;
justify-content: center;
margin-bottom: 1.5rem;
}
.history {
text-align: left;
padding: 1rem;
background: white;
border-radius: 4px;
margin-top: 1rem;
}
.history h3 {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
}
.history ul {
list-style: none;
padding: 0;
margin: 0;
}
.history li {
display: flex;
gap: 1rem;
padding: 0.3rem 0;
border-bottom: 1px solid #eee;
font-size: 0.9rem;
}
.action { color: #ff3e00; }
.value { font-weight: bold; }
.time { color: #999; margin-left: auto; }
</style>
七、运行项目 #
7.1 启动开发服务器 #
bash
npm run dev
7.2 访问应用 #
打开浏览器访问 http://localhost:5173
八、总结 #
本节我们学习了:
| 知识点 | 说明 |
|---|---|
| 组件结构 | script、template、style 三部分 |
| 响应式声明 | $: 或 $state/$derived |
| 事件处理 | on:click 或 onclick |
| 条件渲染 | {#if}...{/if} |
| 列表渲染 | {#each}...{/each} |
| 样式作用域 | style 标签内的样式自动作用域化 |
| 组件复用 | 通过 props 和 slot 实现组件复用 |
最后更新:2026-03-28