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

Svelte模板语法入门:HTML与JS的完美结合

2023-04-141.4k 阅读

Svelte 模板语法基础:绑定

  1. 文本绑定 在 Svelte 中,将 JavaScript 变量的值显示在 HTML 中是非常常见的操作。这可以通过文本绑定来实现。 假设我们有一个 Svelte 组件,在 <script> 标签内定义一个变量:
<script>
    let name = 'John';
</script>

<p>Hello, {name}!</p>

在上述代码中,{name} 就是文本绑定的示例。花括号将 JavaScript 表达式嵌入到 HTML 模板中,Svelte 会在渲染时将 name 变量的值替换到这里。

文本绑定不仅支持简单变量,还可以使用更复杂的 JavaScript 表达式。例如:

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

<p>The sum of {num1} and {num2} is {num1 + num2}.</p>

这里,{num1 + num2} 是一个算术表达式,Svelte 会计算其结果并显示在 HTML 中。

  1. 属性绑定 属性绑定用于将 JavaScript 变量的值绑定到 HTML 元素的属性上。例如,我们想根据一个变量来设置 <img> 元素的 src 属性:
<script>
    let imageSrc = 'https://example.com/image.jpg';
</script>

<img {src}>

这里,{src} 是一种简写形式,等同于 <img src={imageSrc}>。这种简写方式使得代码更加简洁,当属性名和变量名相同时可以直接使用。

对于布尔属性,如 <input> 元素的 checked 属性,Svelte 的处理方式也很直观。假设我们有一个表示复选框是否选中的变量:

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

<input type="checkbox" {checked}>

如果 isCheckedtrue,则 checked 属性会被添加到 <input> 元素上,复选框将被选中;反之则不会添加该属性,复选框未选中。

  1. 双向绑定 双向绑定允许在 HTML 元素和 JavaScript 变量之间建立双向的数据流动。这在处理用户输入时非常有用,比如文本输入框。 以下是一个双向绑定文本输入框的示例:
<script>
    let userInput = '';
</script>

<input type="text" bind:value={userInput}>
<p>You entered: {userInput}</p>

在这个例子中,当用户在输入框中输入内容时,userInput 变量的值会实时更新。同时,如果通过 JavaScript 代码改变 userInput 的值,输入框中的内容也会相应改变。

双向绑定还可以应用于其他表单元素,如 <select> 元素。假设我们有一个选项列表和一个用于存储选中值的变量:

<script>
    let selectedOption = 'option2';
    let options = ['option1', 'option2', 'option3'];
</script>

<select bind:value={selectedOption}>
    {#each options as option}
        <option value={option}>{option}</option>
    {/each}
</select>
<p>You selected: {selectedOption}</p>

这里,用户在 <select> 元素中选择不同的选项时,selectedOption 变量的值会改变,同时如果通过 JavaScript 改变 selectedOption 的值,<select> 元素也会自动选中相应的选项。

条件渲染

  1. if 块 在 Svelte 中,if 块用于根据条件决定是否渲染某部分 HTML 内容。语法如下:
<script>
    let isLoggedIn = true;
</script>

{#if isLoggedIn}
    <p>Welcome, user!</p>
{:else}
    <p>Please log in.</p>
{/if}

在上述代码中,{#if isLoggedIn} 开始一个条件块。如果 isLoggedIntrue,则会渲染 <p>Welcome, user!</p>;否则,会渲染 {:else} 后面的 <p>Please log in.</p>

if 块还可以有多个分支,使用 {:else if} 语法。例如:

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

{#if score >= 90}
    <p>You got an A!</p>
{:else if score >= 80}
    <p>You got a B!</p>
{:else if score >= 70}
    <p>You got a C!</p>
{:else}
    <p>You need to improve.</p>
{/if}

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

  1. null 和 undefined 的处理 Svelte 对 nullundefined 值在 if 块中有特殊的处理。例如:
<script>
    let data;
</script>

{#if data}
    <p>The data is: {data}</p>
{:else}
    <p>No data available.</p>
{/if}

如果 datanullundefined,则会渲染 {:else} 部分的内容。这在处理可能未加载数据的情况时很有用,比如从 API 获取数据。

列表渲染

  1. each 块 each 块用于遍历数组并为每个数组元素渲染相同结构的 HTML 内容。假设我们有一个包含用户名字的数组:
<script>
    let users = ['Alice', 'Bob', 'Charlie'];
</script>

{#each users as user}
    <p>{user}</p>
{/each}

在这个例子中,{#each users as user} 表示遍历 users 数组,user 是每次迭代的数组元素。对于 users 数组中的每个名字,都会渲染一个 <p> 元素显示该名字。

  1. 索引的使用each 块中,我们还可以获取当前迭代的索引。语法如下:
<script>
    let numbers = [1, 2, 3, 4, 5];
</script>

{#each numbers as number, index}
    <p>Index {index}: {number}</p>
{/each}

这里,index 就是当前迭代的索引,从 0 开始。我们可以在 HTML 模板中使用它来显示元素的索引信息。

  1. key 的重要性 当使用 each 块渲染列表时,为每个元素提供一个唯一的 key 是非常重要的。这有助于 Svelte 更高效地更新列表。例如,我们有一个包含用户对象的数组,每个用户对象有一个唯一的 id
<script>
    let users = [
        { id: 1, name: 'Alice' },
        { id: 2, name: 'Bob' },
        { id: 3, name: 'Charlie' }
    ];
</script>

{#each users as user (user.id)}
    <p>{user.name}</p>
{/each}

这里,(user.id) 就是为每个 user 元素指定的 key。当数组中的元素顺序改变或元素被添加、删除时,Svelte 可以通过 key 更准确地更新 DOM,而不是重新渲染整个列表。

事件处理

  1. 基本事件绑定 在 Svelte 中,绑定事件处理函数到 HTML 元素非常简单。例如,为一个按钮绑定点击事件:
<script>
    function handleClick() {
        console.log('Button clicked!');
    }
</script>

<button on:click={handleClick}>Click me</button>

这里,on:click 表示绑定 click 事件,{handleClick} 是事件处理函数。当按钮被点击时,handleClick 函数会被调用,控制台会输出 Button clicked!

  1. 事件对象的访问 许多事件会提供一个事件对象,包含与事件相关的信息。在 Svelte 中,可以通过事件处理函数的参数来访问这个事件对象。例如,处理输入框的 input 事件:
<script>
    function handleInput(event) {
        console.log('Input value:', event.target.value);
    }
</script>

<input type="text" on:input={handleInput}>

handleInput 函数中,event 参数就是输入事件的事件对象。我们可以通过 event.target.value 获取输入框的当前值。

  1. 修饰符的使用 Svelte 提供了一些事件修饰符,用于对事件处理进行更精细的控制。例如,preventDefault 修饰符可以阻止事件的默认行为。对于表单的 submit 事件,默认行为是提交表单并刷新页面,我们可以使用 preventDefault 修饰符来阻止这种行为:
<script>
    function handleSubmit(event) {
        console.log('Form submitted, but not actually submitted to server.');
    }
</script>

<form on:submit|preventDefault={handleSubmit}>
    <input type="submit" value="Submit">
</form>

这里,|preventDefault 就是修饰符,它会在 handleSubmit 函数被调用前阻止表单的默认提交行为。

组件间通信

  1. 父组件向子组件传值 在 Svelte 中,父组件向子组件传递数据是通过属性(props)实现的。首先,创建一个子组件 Child.svelte
<script>
    export let message;
</script>

<p>{message}</p>

这里,export let message 声明了一个名为 message 的属性,子组件可以接收来自父组件的值。

然后,在父组件 Parent.svelte 中使用子组件并传递数据:

<script>
    import Child from './Child.svelte';
    let parentMessage = 'Hello from parent!';
</script>

<Child message={parentMessage} />

在父组件中,通过 <Child message={parentMessage} />parentMessage 的值传递给子组件的 message 属性,子组件会显示这个值。

  1. 子组件向父组件传值 子组件向父组件传值通常通过自定义事件实现。在子组件 Child.svelte 中:
<script>
    import { createEventDispatcher } from'svelte';
    const dispatch = createEventDispatcher();
    function sendDataToParent() {
        dispatch('custom-event', { data: 'Some data from child' });
    }
</script>

<button on:click={sendDataToParent}>Send data to parent</button>

这里,createEventDispatcher 用于创建一个事件分发器 dispatchsendDataToParent 函数通过 dispatch('custom - event', { data: 'Some data from child' }) 触发一个自定义事件 custom - event,并传递数据。

在父组件 Parent.svelte 中监听这个自定义事件:

<script>
    import Child from './Child.svelte';
    function handleCustomEvent(event) {
        console.log('Received data from child:', event.detail.data);
    }
</script>

<Child on:custom-event={handleCustomEvent} />

父组件通过 on:custom - event={handleCustomEvent} 监听子组件触发的 custom - event 事件,handleCustomEvent 函数中的 event.detail.data 可以获取子组件传递的数据。

  1. 跨组件通信(非父子关系) 对于非父子关系的组件之间的通信,可以使用一个共享的状态管理机制。一种简单的方法是通过创建一个独立的 JavaScript 文件来管理共享状态。例如,创建 store.js
import { writable } from'svelte/store';

export const sharedData = writable('Initial value');

然后在两个非父子组件 ComponentA.svelteComponentB.svelte 中使用这个共享状态: 在 ComponentA.svelte 中:

<script>
    import { sharedData } from './store.js';
    function updateSharedData() {
        sharedData.set('New value from ComponentA');
    }
</script>

<button on:click={updateSharedData}>Update shared data</button>

ComponentB.svelte 中:

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

<p>The shared data is: {data}</p>

ComponentA.svelte 中,通过 sharedData.set 方法更新共享数据。在 ComponentB.svelte 中,通过 sharedData.subscribe 方法订阅共享数据的变化,并更新本地变量 data 以反映最新的值。

响应式声明

  1. 基本响应式变量 在 Svelte 中,声明响应式变量非常简单。当一个变量的值发生变化时,与之相关的 DOM 会自动更新。例如:
<script>
    let count = 0;
    function increment() {
        count++;
    }
</script>

<p>The count is: {count}</p>
<button on:click={increment}>Increment</button>

这里,count 是一个普通的 JavaScript 变量。当点击按钮调用 increment 函数使 count 的值增加时,<p>The count is: {count}</p> 部分的 DOM 会自动更新,显示最新的 count 值。

  1. 响应式声明块 Svelte 还提供了响应式声明块($:),用于在变量变化时执行一些副作用操作。例如:
<script>
    let num1 = 5;
    let num2 = 3;
    let sum;
    $: sum = num1 + num2;
</script>

<p>The sum of {num1} and {num2} is {sum}</p>
<button on:click={() => num1++}>Increment num1</button>
<button on:click={() => num2++}>Increment num2</button>

在这个例子中,$: sum = num1 + num2; 是一个响应式声明块。当 num1num2 的值发生变化时,sum 会重新计算,并且 <p>The sum of {num1} and {num2} is {sum}</p> 会自动更新。

  1. 派生状态 派生状态是基于其他响应式变量计算出来的响应式值。例如,我们有一个包含任务的数组,并且想计算已完成任务的数量:
<script>
    let tasks = [
        { id: 1, text: 'Task 1', completed: true },
        { id: 2, text: 'Task 2', completed: false },
        { id: 3, text: 'Task 3', completed: true }
    ];
    let completedTaskCount;
    $: completedTaskCount = tasks.filter(task => task.completed).length;
</script>

<p>Number of completed tasks: {completedTaskCount}</p>

这里,completedTaskCount 是一个派生状态,它基于 tasks 数组计算得出。当 tasks 数组中的任务完成状态发生变化时,completedTaskCount 会自动更新,相关的 DOM 也会更新显示最新的已完成任务数量。

模板中的样式

  1. 局部样式 在 Svelte 组件中,<style> 标签定义的样式是局部作用域的,只应用于该组件。例如:
<script>
    let isActive = false;
</script>

<style>
   .active {
        background - color: lightblue;
    }
</style>

<button class: active={isActive}>Click me</button>

在这个例子中,.active 类的样式只应用于当前组件中的按钮。class: active={isActive} 表示当 isActivetrue 时,按钮会添加 .active 类,从而应用相应的样式。

  1. 全局样式 如果需要定义全局样式,可以在 Svelte 应用的入口文件(通常是 main.js)中导入一个全局样式文件。例如,创建 global.css
body {
    font - family: Arial, sans - serif;
    margin: 0;
    padding: 0;
}

然后在 main.js 中导入:

import './global.css';
import App from './App.svelte';

const app = new App({
    target: document.body
});

export default app;

这样,global.css 中的样式就会应用到整个应用中。

  1. 动态样式绑定 Svelte 支持动态绑定样式属性。例如,根据一个变量动态改变元素的颜色:
<script>
    let color ='red';
    function changeColor() {
        color = 'blue';
    }
</script>

<button style: color={color} on:click={changeColor}>Change color</button>

这里,style: color={color} 将按钮的 color 样式属性绑定到 color 变量。当点击按钮调用 changeColor 函数改变 color 的值时,按钮的文本颜色会动态更新。

过渡与动画

  1. 过渡效果 Svelte 提供了多种内置的过渡效果,如淡入淡出(fade)、滑动(slide)等。要应用过渡效果,首先需要导入相应的过渡函数。例如,为一个元素添加淡入过渡效果:
<script>
    import { fade } from'svelte/transition';
    let showElement = false;
    function toggleElement() {
        showElement =!showElement;
    }
</script>

<button on:click={toggleElement}>Toggle element</button>

{#if showElement}
    <div transition: fade>
        This is a fading element.
    </div>
{/if}

在这个例子中,import { fade } from'svelte/transition'; 导入了 fade 过渡函数。<div transition: fade> 表示当 showElement 变量变化时,<div> 元素会有淡入淡出的过渡效果。

  1. 动画效果 动画效果可以通过 animate 指令实现。例如,为一个元素添加位置移动的动画:
<script>
    import { animate } from'svelte/animate';
    let x = 0;
    function startAnimation() {
        animate('x', 100, {
            duration: 1000,
            easing: 'ease - out'
        });
    }
</script>

<button on:click={startAnimation}>Start animation</button>
<div style="position: relative; left: {x}px;">Animated element</div>

这里,animate('x', 100, { duration: 1000, easing: 'ease - out' }) 表示将 x 的值从当前值动画过渡到 100,持续时间为 1000 毫秒,缓动函数为 ease - out<div style="position: relative; left: {x}px;"> 根据 x 的值动态改变元素的位置,从而实现动画效果。

  1. 自定义过渡与动画 除了内置的过渡和动画,Svelte 还允许创建自定义的过渡和动画。例如,创建一个自定义的旋转过渡效果:
<script>
    function customRotate(node, params) {
        const start = window.getComputedStyle(node).transform;
        const end = `rotate(${params.degrees}deg)`;
        return {
            duration: params.duration || 1000,
            css: t => `transform: ${t === 0? start : (t === 1? end : `rotate(${t * params.degrees}deg)`)}`
        };
    }
    let showElement = false;
    function toggleElement() {
        showElement =!showElement;
    }
</script>

<button on:click={toggleElement}>Toggle element</button>

{#if showElement}
    <div transition: customRotate={{ degrees: 360, duration: 2000 }}>
        This is a rotating element.
    </div>
{/if}

在这个例子中,customRotate 函数定义了一个自定义的旋转过渡效果。transition: customRotate={{ degrees: 360, duration: 2000 }} 将这个自定义过渡应用到 <div> 元素上,使其在显示和隐藏时会有旋转 360 度、持续 2000 毫秒的过渡效果。

通过以上对 Svelte 模板语法各个方面的详细介绍,相信读者已经对 Svelte 中 HTML 与 JS 的完美结合有了深入的理解,能够更加熟练地使用 Svelte 进行前端开发。