pin_drop当前位置:知识文库 ❯ 图文
框架集成:19 Svelte模板与HTM - 详细教程与实战指南
目录
一、教程简介
Svelte模板语法是对HTML的自然扩展,使用{#if}、{#each}、{#await}等块语法实现条件渲染、列表渲染和异步处理。Svelte的事件系统使用on:指令,双向绑定使用bind:指令,Store通过$前缀自动订阅。本教程将详细介绍Svelte模板语法、条件渲染、列表渲染、事件处理、双向绑定、Store、插槽和响应式语句的使用。
二、插值与属性绑定
Svelte使用花括号{}进行插值,支持属性绑定、事件绑定和双向绑定。
代码示例
<!-- 插值 -->
<h1>{title}</h1>
<p>{user.name} - {user.email}</p>
<p>{count * 2}</p>
<p>{isActive ? '激活' : '未激活'}</p>
<!-- 属性绑定 -->
<img src={imageUrl} alt={imageAlt} />
<!-- 简写:属性名与变量名相同时 -->
<img {src} {alt} />
<!-- HTML属性 -->
<div class="card {isActive ? 'active' : ''}"></div>
<div class="card {isActive && 'active'} {isDisabled && 'disabled'}"></div>
<!-- style绑定 -->
<div style="color: {textColor}; font-size: {fontSize}px;"></div>
<div style="color: {textColor}" style:font-size="{fontSize}px"></div>
<!-- 事件绑定 -->
<button on:click={handleClick}>点击</button>
<button on:click={() => count += 1}>+1</button>
<button on:click|once={handleClick}>只触发一次</button>
<button on:click|preventDefault={handleSubmit}>阻止默认</button>
<!-- 事件修饰符(可链式) -->
on:click|stopPropagation|preventDefault={handler}
on:submit|preventDefault={onSubmit}
on:keydown|enter={onEnter}
<!-- 双向绑定 -->
<input bind:value={name} />
<textarea bind:value={bio}></textarea>
<input type="checkbox" bind:checked={agree} />
<input type="range" bind:value={level} min="0" max="10" />
<select bind:value={selected}>
<option value="a">A</option>
<option value="b">B</option>
</select>
<!-- 绑定this(获取DOM引用) -->
<input bind:this={inputEl} />
// script中: let inputEl;
// onMount(() => inputEl.focus());三、条件渲染 {#if}
Svelte使用{#if}块语法进行条件渲染,支持{:else if}和{:else}分支。
代码示例
<!-- 基本条件 -->
{#if count > 10}
<p>计数超过10</p>
{:else if count > 5}
<p>计数在5-10之间</p>
{:else}
<p>计数在5以下</p>
{/if}
<!-- 简洁条件(内联) -->
<p>{count > 0 ? '正数' : '非正数'}</p>
<!-- 逻辑与(类似React) -->
{#if items.length > 0}
<ul>
{#each items as item}
<li>{item.name}</li>
{/each}
</ul>
{/if}四、列表渲染 {#each}
Svelte使用{#each}进行列表渲染,支持索引、key和空列表处理。
代码示例
<!-- 基本列表 -->
<ul>
{#each items as item}
<li>{item.name}</li>
{/each}
</ul>
<!-- 带索引 -->
{#each items as item, i}
<li>{i + 1}. {item.name}</li>
{/each}
<!-- 带key(推荐,帮助diff) -->
{#each items as item (item.id)}
<li>{item.name}</li>
{/each}
<!-- 带索引和key -->
{#each items as item, i (item.id)}
<li>{i}. {item.name}</li>
{/each}
<!-- else分支(列表为空时) -->
{#each items as item}
<li>{item.name}</li>
{:else}
<li>暂无数据</li>
{/each}
<!-- 嵌套列表 -->
{#each categories as category}
<h3>{category.name}</h3>
<ul>
{#each category.items as item}
<li>{item.name}</li>
{/each}
</ul>
{/each}提示:始终为{#each}提供key参数(如item.id),这有助于Svelte高效更新列表,避免不必要的DOM操作。
五、异步渲染 {#await}
Svelte提供{#await}块语法处理Promise,自动管理加载、成功和错误状态。
代码示例
<!-- 基本异步 -->
{#await fetchData()}
<p>加载中...</p>
{:then data}
<p>数据: {data.name}</p>
{:catch error}
<p>错误: {error.message}</p>
{/await}
<!-- 只处理成功 -->
{#await fetchData() then data}
<p>数据: {data.name}</p>
{/await}
<!-- 分离Promise和结果 -->
<script>
let promise = fetchData();
async function fetchData() {
const res = await fetch('/api/data');
return res.json();
}
function reload() {
promise = fetchData(); // 重新赋值触发更新
}
</script>
{#await promise}
<p>加载中...</p>
{:then data}
<p>{data.name}</p>
<button on:click={reload}>刷新</button>
{:catch error}
<p>出错了: {error}</p>
<button on:click={reload}>重试</button>
{/await}六、Store与插槽
Svelte的Store提供跨组件状态管理,通过$前缀自动订阅。插槽(Slot)支持组件内容分发。
代码示例
<!-- Store使用 -->
<script>
import { writable, derived } from 'svelte/store';
// 创建writable store
const count = writable(0);
// 创建derived store
const doubled = derived(count, $count => $count * 2);
// 组件内使用$前缀自动订阅
function increment() {
$count += 1; // $前缀自动订阅和更新
}
</script>
<p>计数: {$count}</p>
<p>双倍: {$doubled}</p>
<button on:click={increment}>+1</button>
<button on:click={() => $count -= 1}>-1</button>
<!-- 插槽(Slot) -->
<!-- Card.svelte -->
<div class="card">
<div class="header">
<slot name="header">默认标题</slot>
</div>
<div class="body">
<slot>默认内容</slot>
</div>
<div class="footer">
<slot name="footer"></slot>
</div>
</div>
<!-- 使用 -->
<Card>
<svelte:fragment slot="header">
<h3>自定义标题</h3>
</svelte:fragment>
<p>卡片内容</p>
<button slot="footer">底部按钮</button>
</Card>
<!-- svelte:head(设置head内容) -->
<svelte:head>
<title>{pageTitle}</title>
<meta name="description" content={description} />
</svelte:head>
<!-- svelte:window(监听窗口事件) -->
<svelte:window on:resize={handleResize} on:keydown={handleKeydown} />
<!-- svelte:body(监听body事件) -->
<svelte:body on:mouseenter={handleMouseEnter} />
<!-- svelte:element(动态元素) -->
<svelte:element this={tagType}>
动态元素内容
</svelte:element>七、响应式语句详解
Svelte使用$:语法声明响应式计算和副作用。Svelte 5引入了runes($state、$derived、$effect)提供更精确的响应式控制。
代码示例
<!-- $: 响应式声明 -->
<script>
let firstName = '张';
let lastName = '三';
// 响应式计算
$: fullName = firstName + lastName;
$: nameLength = fullName.length;
// 响应式语句(副作用)
$: console.log('姓名变化:', fullName);
// 响应式块
$: {
console.log('firstName:', firstName);
console.log('lastName:', lastName);
console.log('fullName:', fullName);
}
// 响应式条件
$: if (nameLength > 10) {
console.log('名字太长了!');
}
// 响应式依赖声明(Svelte 5+使用$derived和$effect)
// Svelte 4:
$: filtered = items.filter(i => i.active);
// Svelte 5 (runes):
let filtered = $derived(items.filter(i => i.active));
$effect(() => {
console.log('items changed:', items);
});
</script>
<!-- 注意:响应式声明的限制 -->
<!-- Svelte通过静态分析确定依赖,以下写法可能无法正确追踪 -->
// 不推荐:函数调用隐藏依赖
function getActive() { return items.filter(i => i.active); }
$: active = getActive(); // Svelte可能无法追踪items变化
// 推荐:直接在响应式声明中写表达式
$: active = items.filter(i => i.active);
// 不推荐:动态键访问
$: value = obj[key]; // key变化时可能不更新
// 推荐:显式声明依赖
$: key, value = obj[key];八、Svelte模板语法速查表
下面列出Svelte模板的常用语法及其用途。
九、浏览器兼容性
Svelte模板语法编译为标准JavaScript,在所有现代浏览器中完全支持。
十、注意事项与最佳实践
-
{#each}必须加key:使用(item.id)语法提供key,帮助Svelte高效更新列表
-
赋值触发更新:数组和对象必须重新赋值才能触发响应式更新
-
Store用$前缀:$store自动订阅,组件销毁时自动取消订阅
-
事件修饰符链式使用:on:click|stopPropagation|preventDefault
-
bind:this获取DOM引用:替代querySelector,更安全
-
svelte:head设置页面元数据:在组件中设置title和meta标签
代码规范示例
代码示例
<!-- 不推荐:{#each}不加key -->
{#each items as item}
<li>{item.name}</li>
{/each}
<!-- 推荐:带key -->
{#each items as item (item.id)}
<li>{item.name}</li>
{/each}
<!-- 不推荐:复杂内联表达式 -->
<p>{items.filter(i => i.active).map(i => i.name).join(', ')}</p>
<!-- 推荐:使用响应式声明 -->
<script>
$: activeNames = items.filter(i => i.active).map(i => i.name).join(', ');
</script>
<p>{activeNames}</p>
<!-- 不推荐:手动订阅Store -->
import { count } from './stores';
const unsubscribe = count.subscribe(value => { ... });
onDestroy(unsubscribe);
<!-- 推荐:使用$前缀自动订阅 -->
<script>
import { count } from './stores';
</script>
<p>{$count}</p>常见问题
Q1:Svelte的{#each}和Vue的v-for有什么区别?
语法不同但功能相似。Svelte使用{#each items as item (key)},Vue使用v-for="item in items" :key="key"。Svelte的{:else}分支处理空列表更方便。
Q2:bind:value和on:input有什么区别?
bind:value是双向绑定,自动同步输入值和变量;on:input是事件监听,需要手动更新变量。bind:value更简洁,是Svelte推荐的表单处理方式。
Q3:Svelte的Store和React的Context有什么区别?
Store是模块级的响应式状态,可以在任何地方导入使用;Context是组件树内的依赖注入,只能在组件树中传递。Store适合全局状态,Context适合局部状态。
Q4:{#await}和onMount中获取数据哪个好?
{#await}直接在模板中处理加载/成功/错误状态,更声明式;onMount中获取数据更灵活,适合复杂逻辑。简单场景用{#await},复杂场景用onMount。
Q5:Svelte 5的runes是什么?
Runes是Svelte 5引入的新响应式原语,使用$state、$derived、$effect等符号替代$: 语法。Runes提供更精确的响应式控制,支持在.svelte.js文件中使用。
总结:本教程详细介绍了Svelte模板与HTML的关系。Svelte使用{#if}、{#each}、{#await}等块语法实现条件渲染、列表渲染和异步处理,语法简洁直观。事件绑定使用on:指令,支持修饰符链式使用。双向绑定使用bind:指令,覆盖了各种表单控件。Store通过$前缀实现自动订阅,简化了跨组件状态管理。插槽(Slot)支持默认插槽、具名插槽和作用域插槽。响应式声明通过$: 语法实现,Svelte 5引入了runes提供更精确的响应式控制。Svelte的模板语法是最接近原生HTML的,学习成本低,开发效率高。
本文涉及AI创作
内容由AI创作,请仔细甄别