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模板的常用语法及其用途。

语法 用途 示例
{expr} 插值 {name}
{#if}...{:else}...{/if} 条件渲染 {#if show}...{/if}
{#each}...{/each} 列表渲染 {#each items as item}...{/each}
{#await}...{:then}...{:catch}...{/await} 异步渲染 {#await promise}...{/await}
{#key}...{/key} 键值重建 {#key id}...{/key}
on:event 事件绑定 on:click={fn}
bind:property 双向绑定 bind:value={name}
use:action 使用action use:focus
transition: 过渡动画 transition:fade
in:/out: 进入/离开动画 in:fade out:fly
animate: 翻转动画 animate:flip

九、浏览器兼容性

Svelte模板语法编译为标准JavaScript,在所有现代浏览器中完全支持。

特性 Chrome Firefox Safari Edge 说明
Svelte模板 全部 全部 全部 全部 编译为标准JS
{#if}/{#each} 全部 全部 全部 全部 编译时处理
{#await} 全部 全部 全部 全部 编译为Promise处理
bind: 全部 全部 全部 全部 编译为DOM操作
Store 全部 全部 全部 全部 编译为订阅机制
transition: 全部 全部 全部 全部 CSS动画+JS

十、注意事项与最佳实践

  • {#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的,学习成本低,开发效率高。

标签: Svelte模板 条件渲染 列表渲染 事件绑定 双向绑定 Store 插槽 响应式语句

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: 框架集成:18 HTML与Svelte集 - 详细教程与实战指南 下一篇: 框架集成:20 框架路由与HTML - 详细教程与实战指南

poll相关推荐