条件渲染 #
一、基本语法 #
1.1 if 块 #
svelte
<script>
let show = true;
</script>
{#if show}
<p>This is visible</p>
{/if}
1.2 if-else 块 #
svelte
<script>
let count = 5;
</script>
{#if count > 10}
<p>Count is greater than 10</p>
{:else}
<p>Count is 10 or less</p>
{/if}
1.3 if-else if-else 块 #
svelte
<script>
let score = 75;
</script>
{#if score >= 90}
<p>Grade: A</p>
{:else if score >= 80}
<p>Grade: B</p>
{:else if score >= 70}
<p>Grade: C</p>
{:else if score >= 60}
<p>Grade: D</p>
{:else}
<p>Grade: F</p>
{/if}
二、条件渲染场景 #
2.1 显示/隐藏 #
svelte
<script>
let isVisible = false;
function toggle() {
isVisible = !isVisible;
}
</script>
<button onclick={toggle}>
{isVisible ? 'Hide' : 'Show'}
</button>
{#if isVisible}
<div class="content">
This content can be toggled
</div>
{/if}
2.2 加载状态 #
svelte
<script>
let loading = $state(true);
let data = $state(null);
let error = $state(null);
async function fetchData() {
loading = true;
error = null;
try {
const response = await fetch('/api/data');
data = await response.json();
} catch (e) {
error = e.message;
} finally {
loading = false;
}
}
fetchData();
</script>
{#if loading}
<div class="loading">
<span class="spinner"></span>
Loading...
</div>
{:else if error}
<div class="error">
Error: {error}
</div>
{:else if data}
<div class="data">
{#each data as item}
<p>{item.name}</p>
{/each}
</div>
{:else}
<div class="empty">
No data available
</div>
{/if}
2.3 用户状态 #
svelte
<script>
let user = $state(null);
let isLoggedIn = $derived(!!user);
function login() {
user = { name: 'Alice', role: 'admin' };
}
function logout() {
user = null;
}
</script>
{#if isLoggedIn}
<div class="user-panel">
<p>Welcome, {user.name}!</p>
{#if user.role === 'admin'}
<button>Admin Panel</button>
{/if}
<button onclick={logout}>Logout</button>
</div>
{:else}
<div class="login-panel">
<button onclick={login}>Login</button>
</div>
{/if}
2.4 表单验证 #
svelte
<script>
let form = $state({
email: '',
password: ''
});
let touched = $state({});
let errors = $derived({
email: touched.email && !form.email ? 'Email required' : null,
password: touched.password && form.password.length < 6
? 'Password must be at least 6 characters'
: null
});
let isValid = $derived(!errors.email && !errors.password);
</script>
<form>
<div>
<input
type="email"
bind:value={form.email}
onblur={() => touched = { ...touched, email: true }}
/>
{#if errors.email}
<span class="error">{errors.email}</span>
{/if}
</div>
<div>
<input
type="password"
bind:value={form.password}
onblur={() => touched = { ...touched, password: true }}
/>
{#if errors.password}
<span class="error">{errors.password}</span>
{/if}
</div>
{#if isValid}
<button type="submit">Submit</button>
{:else}
<button type="submit" disabled>Submit</button>
{/if}
</form>
三、嵌套条件 #
3.1 多层嵌套 #
svelte
<script>
let user = $state(null);
let notifications = $state([]);
</script>
{#if user}
{#if notifications.length > 0}
{#if notifications.length > 10}
<p>You have many notifications ({notifications.length})</p>
{:else}
<p>You have {notifications.length} notifications</p>
{/if}
{:else}
<p>No notifications</p>
{/if}
{:else}
<p>Please login to see notifications</p>
{/if}
3.2 简化嵌套 #
svelte
<script>
let user = $state(null);
let notifications = $state([]);
let showManyNotifications = $derived(
user && notifications.length > 10
);
let showNormalNotifications = $derived(
user && notifications.length > 0 && notifications.length <= 10
);
let showNoNotifications = $derived(
user && notifications.length === 0
);
</script>
{#if showManyNotifications}
<p>You have many notifications ({notifications.length})</p>
{:else if showNormalNotifications}
<p>You have {notifications.length} notifications</p>
{:else if showNoNotifications}
<p>No notifications</p>
{:else}
<p>Please login to see notifications</p>
{/if}
四、条件与过渡 #
4.1 条件过渡 #
svelte
<script>
import { fade, fly, slide } from 'svelte/transition';
let show = false;
</script>
<button onclick={() => show = !show}>
Toggle
</button>
{#if show}
<div transition:fade>
Fading in and out
</div>
{/if}
{#if show}
<div in:fly={{ y: 50 }} out:fade>
Flying in, fading out
</div>
{/if}
4.2 带延迟的过渡 #
svelte
<script>
import { fade } from 'svelte/transition';
let items = $state([]);
function addItem() {
items = [...items, { id: Date.now() }];
}
function removeItem(id) {
items = items.filter(item => item.id !== id);
}
</script>
<button onclick={addItem}>Add Item</button>
{#each items as item (item.id)}
{#if true}
<div transition:fade={{ delay: items.indexOf(item) * 100 }}>
Item {item.id}
<button onclick={() => removeItem(item.id)}>Remove</button>
</div>
{/if}
{/each}
五、条件渲染 vs CSS 隐藏 #
5.1 条件渲染 #
svelte
{#if show}
<div>This is conditionally rendered</div>
{/if}
特点:
- 元素完全不存在于 DOM 中
- 不占用资源
- 组件状态不保留
5.2 CSS 隐藏 #
svelte
<script>
let show = true;
</script>
<div class:hidden={!show}>
This is hidden with CSS
</div>
<style>
.hidden {
display: none;
}
</style>
特点:
- 元素存在于 DOM 中
- 占用资源
- 组件状态保留
5.3 选择建议 #
text
使用条件渲染:
├── 组件初始化开销大
├── 需要完全移除元素
├── SEO 考虑
└── 性能敏感场景
使用 CSS 隐藏:
├── 需要保留组件状态
├── 频繁切换显示
├── 过渡动画需要
└── 表单输入保留
六、实际应用示例 #
6.1 消息提示组件 #
svelte
<script>
let { type = 'info', message = '', duration = 3000 } = $props();
let visible = $state(false);
export function show(msg, tp = type) {
message = msg;
type = tp;
visible = true;
setTimeout(() => {
visible = false;
}, duration);
}
</script>
{#if visible}
<div class="message {type}" transition:fade>
{message}
<button onclick={() => visible = false}>×</button>
</div>
{/if}
<style>
.message {
padding: 1rem;
border-radius: 4px;
display: flex;
justify-content: space-between;
align-items: center;
}
.info { background: #e3f2fd; color: #1976d2; }
.success { background: #e8f5e9; color: #388e3c; }
.warning { background: #fff3e0; color: #f57c00; }
.error { background: #ffebee; color: #d32f2f; }
</style>
6.2 标签页组件 #
svelte
<script>
let { tabs = [], defaultTab = 0 } = $props();
let activeTab = $state(defaultTab);
</script>
<div class="tabs">
<div class="tab-list">
{#each tabs as tab, index}
<button
class="tab-button"
class:active={activeTab === index}
onclick={() => activeTab = index}
>
{tab.label}
</button>
{/each}
</div>
<div class="tab-content">
{#each tabs as tab, index}
{#if activeTab === index}
<div class="tab-panel" transition:fade>
{tab.content}
</div>
{/if}
{/each}
</div>
</div>
<style>
.tabs {
border: 1px solid #ddd;
border-radius: 4px;
}
.tab-list {
display: flex;
border-bottom: 1px solid #ddd;
}
.tab-button {
padding: 0.75rem 1.5rem;
border: none;
background: none;
cursor: pointer;
border-bottom: 2px solid transparent;
}
.tab-button.active {
border-bottom-color: #ff3e00;
color: #ff3e00;
}
.tab-content {
padding: 1rem;
}
</style>
6.3 步骤向导 #
svelte
<script>
let steps = [
{ title: 'Step 1', description: 'Personal Info' },
{ title: 'Step 2', description: 'Account Setup' },
{ title: 'Step 3', description: 'Confirmation' }
];
let currentStep = $state(0);
let isFirstStep = $derived(currentStep === 0);
let isLastStep = $derived(currentStep === steps.length - 1);
function next() {
if (!isLastStep) currentStep += 1;
}
function prev() {
if (!isFirstStep) currentStep -= 1;
}
</script>
<div class="wizard">
<div class="steps">
{#each steps as step, index}
<div
class="step"
class:active={index === currentStep}
class:completed={index < currentStep}
>
<span class="step-number">
{#if index < currentStep}✓{:else}{index + 1}{/if}
</span>
<span class="step-title">{step.title}</span>
</div>
{/each}
</div>
<div class="content">
{#if currentStep === 0}
<h2>Personal Info</h2>
<input type="text" placeholder="Name" />
{:else if currentStep === 1}
<h2>Account Setup</h2>
<input type="email" placeholder="Email" />
<input type="password" placeholder="Password" />
{:else if currentStep === 2}
<h2>Confirmation</h2>
<p>Review your information</p>
{/if}
</div>
<div class="actions">
{#if !isFirstStep}
<button onclick={prev}>Previous</button>
{/if}
{#if !isLastStep}
<button onclick={next}>Next</button>
{:else}
<button>Finish</button>
{/if}
</div>
</div>
七、性能考虑 #
7.1 避免复杂条件 #
svelte
<script>
let data = $state([]);
let hasData = $derived(data.length > 0);
let hasManyItems = $derived(data.length > 100);
let hasErrors = $derived(data.some(item => item.error));
</script>
{#if hasErrors}
<div class="error">Some items have errors</div>
{:else if hasManyItems}
<div class="warning">Many items</div>
{:else if hasData}
<div class="success">Data loaded</div>
{:else}
<div class="empty">No data</div>
{/if}
7.2 使用 key 优化 #
svelte
<script>
let items = $state([]);
let selectedId = $state(null);
</script>
{#each items as item (item.id)}
{#if item.id === selectedId}
<div class="selected">
{item.name} (selected)
</div>
{:else}
<div class="item">
{item.name}
</div>
{/if}
{/each}
八、总结 #
| 语法 | 说明 |
|---|---|
{#if condition} |
条件开始 |
{:else if condition} |
否则如果 |
{:else} |
否则 |
{/if} |
条件结束 |
条件渲染要点:
- 使用
{#if}开始条件块 - 使用
{:else}和{:else if}添加分支 - 必须以
{/if}结束 - 可以嵌套使用
- 结合过渡动画提升用户体验
- 合理选择条件渲染或 CSS 隐藏
最后更新:2026-03-28