MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Svelte 模板语法详解:构建动态用户界面

2024-12-265.8k 阅读

1. Svelte 模板语法基础

Svelte 是一种现代的前端 JavaScript 框架,它以其独特的编译时特性和简洁的模板语法而闻名。在 Svelte 中,模板是构建用户界面的核心部分,通过简洁的语法可以创建动态、交互式的 UI。

1.1 元素和文本

最基本的,Svelte 模板可以包含普通的 HTML 元素。例如:

<p>这是一个简单的段落。</p>

当需要在模板中插入动态文本时,可以使用花括号 {}。比如:

<script>
    let name = '张三';
</script>

<p>你好,{name}!</p>

这里,{name} 会被变量 name 的值所替换。如果 name 的值发生变化,相应的文本也会自动更新。

1.2 表达式

在花括号内不仅可以放置变量,还能使用 JavaScript 表达式。例如:

<script>
    let num1 = 5;
    let num2 = 3;
</script>

<p>{num1 + num2} 的结果是 {num1 + num2}</p>

这在进行简单的计算或者逻辑判断并展示结果时非常有用。不过要注意,Svelte 模板中的表达式不能包含语句,比如 if 语句、for 循环等(但有对应的 Svelte 特定语法来实现类似功能,后续会介绍)。

2. 条件渲染

在构建用户界面时,经常需要根据某些条件来决定是否渲染某个元素或组件。Svelte 使用 {#if} 块来实现条件渲染。

2.1 {#if} 基本用法

<script>
    let isLoggedIn = false;
</script>

{#if isLoggedIn}
    <p>欢迎回来!</p>
{:else}
    <p>请登录。</p>
{/if}

在这个例子中,如果 isLoggedIntrue,则会渲染 <p>欢迎回来!</p>;否则,渲染 <p>请登录。</p>{:else} 部分是可选的,如果不需要在条件不满足时渲染额外内容,可以省略。

2.2 {#if}

类似于 JavaScript 中的 if - else if - else 链,Svelte 也有类似的语法:

<script>
    let score = 75;
</script>

{#if score >= 90}
    <p>优秀!</p>
{:else if score >= 70}
    <p>良好。</p>
{:else}
    <p>需努力。</p>
{/if}

这里根据 score 的不同值,会渲染不同的 <p> 元素。

3. 列表渲染

展示列表数据是前端开发中常见的需求,Svelte 通过 {#each} 块来实现列表渲染。

3.1 渲染简单数组

假设我们有一个水果数组:

<script>
    let fruits = ['苹果', '香蕉', '橙子'];
</script>

<ul>
    {#each fruits as fruit}
        <li>{fruit}</li>
    {/each}
</ul>

在这个例子中,{#each fruits as fruit} 表示对 fruits 数组中的每一个元素进行迭代,fruit 是每次迭代的当前元素。{/each} 标记迭代块的结束。

3.2 带索引的列表渲染

有时候我们可能还需要知道当前元素在数组中的索引,这可以通过在 as 后添加第二个参数来实现:

<script>
    let fruits = ['苹果', '香蕉', '橙子'];
</script>

<ul>
    {#each fruits as fruit, index}
        <li>{index + 1}. {fruit}</li>
    {/each}
</ul>

这样,每个列表项前会显示其在数组中的序号(从 1 开始)。

3.3 渲染对象数组

如果数组中的元素是对象,同样可以轻松渲染:

<script>
    let users = [
        { name: '张三', age: 25 },
        { name: '李四', age: 30 },
        { name: '王五', age: 22 }
    ];
</script>

<ul>
    {#each users as user}
        <li>{user.name},{user.age} 岁</li>
    {/each}
</ul>

这里我们可以直接访问对象的属性来展示相关信息。

4. 绑定

Svelte 的绑定机制允许我们在组件的状态和 DOM 元素之间建立双向数据流动,这在处理用户输入等场景下非常有用。

4.1 文本输入绑定

对于输入框,我们可以使用 bind:value 来实现双向绑定:

<script>
    let username = '';
</script>

<input type="text" bind:value={username}>
<p>你输入的是:{username}</p>

当用户在输入框中输入内容时,username 变量的值会实时更新,同时 <p> 元素中的文本也会随之改变。反之,如果通过代码改变 username 的值,输入框中的内容也会相应更新。

4.2 复选框和单选框绑定

对于复选框,使用 bind:checked

<script>
    let isChecked = false;
</script>

<input type="checkbox" bind:checked={isChecked}>
<p>复选框状态:{isChecked ? '已选中' : '未选中'}</p>

对于单选框,假设有一组性别选项:

<script>
    let gender = '男';
</script>

<input type="radio" name="gender" value="男" bind:group={gender}>男
<input type="radio" name="gender" value="女" bind:group={gender}>女
<p>你选择的性别是:{gender}</p>

这里 bind:group 用于单选框组,将所有同组的单选框与同一个变量绑定,实现互斥选择。

5. 组件通信

在大型应用中,组件之间的通信至关重要。Svelte 通过一些简单的机制来实现父子组件、兄弟组件之间的通信。

5.1 父子组件通信 - 传递属性

父组件向子组件传递数据是通过属性(props)来实现的。 首先创建一个子组件 Child.svelte

<script>
    export let message;
</script>

<p>{message}</p>

在父组件中使用该子组件并传递属性:

<script>
    import Child from './Child.svelte';
    let greeting = '你好,子组件!';
</script>

<Child message={greeting} />

这里,父组件将 greeting 变量的值通过 message 属性传递给了子组件 Child

5.2 父子组件通信 - 事件

子组件向父组件传递数据通常通过事件来实现。 修改 Child.svelte 如下:

<script>
    import { createEventDispatcher } from'svelte';
    const dispatch = createEventDispatcher();
    function sendData() {
        dispatch('customEvent', { data: '子组件的数据' });
    }
</script>

<button on:click={sendData}>发送数据给父组件</button>

在父组件中监听该事件:

<script>
    import Child from './Child.svelte';
    function handleCustomEvent(event) {
        console.log('收到子组件的数据:', event.detail.data);
    }
</script>

<Child on:customEvent={handleCustomEvent} />

当子组件中的按钮被点击时,会触发 customEvent 事件,并将数据传递给父组件,父组件通过 handleCustomEvent 函数来处理该事件。

5.3 兄弟组件通信

兄弟组件之间的通信可以通过一个共享的状态管理机制或者通过共同的父组件来间接实现。 例如,使用一个简单的 store(类似于 Vuex 或 Redux 中的 store 概念)来实现兄弟组件通信。 首先创建一个 store.js 文件:

import { writable } from'svelte/store';

export const sharedStore = writable('初始数据');

然后在两个兄弟组件 Brother1.svelteBrother2.svelte 中使用这个 store。 Brother1.svelte

<script>
    import { sharedStore } from './store.js';
    function updateStore() {
        sharedStore.update(data => '新的数据');
    }
</script>

<button on:click={updateStore}>更新共享数据</button>

Brother2.svelte

<script>
    import { sharedStore } from './store.js';
    let data;
    sharedStore.subscribe(value => {
        data = value;
    });
</script>

<p>共享数据:{data}</p>

这样,当 Brother1.svelte 中的按钮点击更新 sharedStore 时,Brother2.svelte 会自动收到数据变化并更新显示。

6. 响应式声明

Svelte 提供了强大的响应式声明语法,使得处理状态变化变得简洁明了。

6.1 $: 响应式语句

当一个变量发生变化时,我们可能希望执行一些额外的操作。例如:

<script>
    let num1 = 5;
    let num2 = 3;
    let result;
    $: result = num1 + num2;
</script>

<p>{num1} + {num2} = {result}</p>

这里 $: 标记了一个响应式语句,当 num1num2 的值发生变化时,result 会自动重新计算。

6.2 响应式声明块

我们还可以使用响应式声明块来执行更复杂的逻辑:

<script>
    let count = 0;
    let message;
    $: {
        if (count === 0) {
            message = '数量为零';
        } else if (count > 0 && count < 10) {
            message = '数量较少';
        } else {
            message = '数量较多';
        }
    }
</script>

<button on:click={() => count++}>增加数量</button>
<p>{message}</p>

在这个例子中,当 count 的值发生变化时,整个响应式声明块内的逻辑会重新执行,从而更新 message 的值。

7. 插槽(Slots)

插槽是 Svelte 中一种强大的机制,允许我们在组件中定义可插入内容的区域。

7.1 匿名插槽

在组件 Parent.svelte 中定义一个匿名插槽:

<div class="parent">
    <slot></slot>
</div>

在使用该组件时,可以在组件标签内插入任何内容:

<script>
    import Parent from './Parent.svelte';
</script>

<Parent>
    <p>这是插入到插槽中的内容。</p>
</Parent>

这里 <p> 元素的内容会被插入到 Parent.svelte 组件的 <slot> 位置。

7.2 具名插槽

具名插槽允许我们在组件中定义多个插槽,并通过名称来区分。 在 ComplexParent.svelte 中定义具名插槽:

<div class="complex - parent">
    <slot name="header"></slot>
    <main>
        <slot></slot>
    </main>
    <slot name="footer"></slot>
</div>

在使用该组件时,可以通过 slot 属性指定插入到哪个具名插槽:

<script>
    import ComplexParent from './ComplexParent.svelte';
</script>

<ComplexParent>
    <h1 slot="header">标题</h1>
    <p>主要内容</p>
    <p slot="footer">页脚内容</p>
</ComplexParent>

这样,不同的内容会被插入到对应的具名插槽位置。

8. 过渡和动画

Svelte 提供了简单而强大的过渡和动画功能,能够为用户界面增添生动性。

8.1 过渡效果

过渡效果通常在元素的显示或隐藏时应用。例如,淡入淡出效果:

<script>
    import { fade } from'svelte/transition';
    let isVisible = true;
    function toggleVisibility() {
        isVisible =!isVisible;
    }
</script>

<button on:click={toggleVisibility}>切换可见性</button>
{#if isVisible}
    <div transition:fade>
        <p>这是一个带有淡入淡出过渡的元素。</p>
    </div>
{/if}

这里 transition:fade 应用了淡入淡出过渡效果,当 isVisible 的值改变时,<div> 元素会以淡入或淡出的方式显示或隐藏。

8.2 动画

动画可以对元素的属性进行动态变化。例如,对一个元素进行缩放动画:

<script>
    import { scale } from'svelte/animate';
    let scaleValue = 1;
    function startAnimation() {
        scaleValue = 2;
    }
</script>

<button on:click={startAnimation}>开始动画</button>
<div animate:scale={scaleValue}>
    <p>这是一个带有缩放动画的元素。</p>
</div>

当点击按钮时,scaleValue 从 1 变为 2,<div> 元素会以缩放的动画效果进行变化。

通过以上对 Svelte 模板语法各个方面的详细介绍,相信你已经对如何使用 Svelte 构建动态用户界面有了深入的理解。在实际项目中,灵活运用这些语法,可以高效地创建出丰富、交互式的前端应用。无论是简单的页面展示还是复杂的单页应用,Svelte 的模板语法都能提供强大的支持。