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

Svelte 组件化开发入门:从零开始创建你的第一个组件

2021-03-293.8k 阅读

1. Svelte 简介

Svelte 是一种新型的前端框架,与 React、Vue 和 Angular 等框架有所不同。它并非在浏览器端通过虚拟 DOM 来操作真实 DOM,而是在编译阶段将组件代码转换为高效的、直接操作 DOM 的 JavaScript 代码。这使得 Svelte 应用在运行时非常轻量,性能表现出色。

Svelte 的核心理念是“编写更少,得到更多”。它的语法简洁直观,上手难度相对较低。同时,Svelte 支持响应式编程,能够轻松地处理数据变化与 DOM 更新之间的关系。

2. 环境搭建

在开始创建 Svelte 组件之前,需要搭建好开发环境。

2.1 安装 Node.js

Svelte 项目依赖 Node.js,因此首先要确保系统中安装了 Node.js。可以从 Node.js 官方网站 下载适合系统的安装包进行安装。安装完成后,在命令行中输入 node -vnpm -v 来检查是否安装成功,这两个命令会分别输出版本号。

2.2 创建 Svelte 项目

有多种方式来创建 Svelte 项目,这里推荐使用官方提供的 degit 工具。degit 是一个简单的项目脚手架工具,可以基于模板快速创建项目。

首先,全局安装 degit

npm install -g degit

然后,使用 degit 创建一个新的 Svelte 项目。例如,要创建一个名为 my - svelte - app 的项目,可以执行以下命令:

degit sveltejs/template my - svelte - app
cd my - svelte - app
npm install

上述命令中,degit sveltejs/template my - svelte - app 会基于 Svelte 官方模板创建一个名为 my - svelte - app 的项目目录。进入该目录后,执行 npm install 安装项目所需的依赖。

2.3 启动开发服务器

项目依赖安装完成后,可以启动开发服务器来预览项目。在项目目录下执行:

npm run dev

执行该命令后,开发服务器会启动,并输出一个本地访问链接,例如 http://localhost:5000。在浏览器中打开该链接,就能看到默认的 Svelte 应用界面。

3. Svelte 组件基础

3.1 组件的概念

在 Svelte 中,组件是构成应用的基本单元。每个组件都有自己的逻辑、样式和模板。组件可以包含子组件,从而构建出复杂的应用结构。

3.2 组件文件结构

Svelte 组件通常以 .svelte 为后缀名。一个典型的 Svelte 组件文件包含三个部分:脚本部分(<script>)、样式部分(<style>)和模板部分(<template>)。

例如,创建一个简单的 Hello.svelte 组件:

<script>
    let name = 'World';
</script>

<style>
    h1 {
        color: blue;
    }
</style>

<template>
    <h1>Hello, {name}!</h1>
</template>

在上述代码中:

  • <script> 标签内定义了一个变量 name 并初始化为 'World'。这部分用于编写组件的逻辑代码,比如声明变量、定义函数等。
  • <style> 标签内定义了 h1 元素的样式,使其文本颜色为蓝色。这里的样式作用域仅限于当前组件,不会影响其他组件。
  • <template> 标签内是组件的模板部分,使用 {} 语法将 name 变量插入到 <h1> 标签中,形成最终的 DOM 结构。

4. 创建第一个 Svelte 组件

4.1 创建组件文件

在项目的 src 目录下创建一个新的文件,例如 MyFirstComponent.svelte

4.2 编写组件脚本部分

MyFirstComponent.svelte 中,首先编写脚本部分:

<script>
    let message = 'This is my first Svelte component';
    function handleClick() {
        message = 'Button clicked!';
    }
</script>

在上述代码中,定义了一个字符串变量 message,并初始化为 'This is my first Svelte component'。还定义了一个 handleClick 函数,当按钮被点击时,该函数会修改 message 的值。

4.3 编写组件样式部分

接着编写样式部分:

<style>
    button {
        background - color: green;
        color: white;
        padding: 10px 20px;
        border: none;
        border - radius: 5px;
        cursor: pointer;
    }
</style>

上述样式定义了按钮的背景颜色为绿色,文本颜色为白色,设置了内边距、边框和圆角,并添加了鼠标悬停时的指针样式。

4.4 编写组件模板部分

最后编写模板部分:

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

在模板中,首先显示 message 变量的值,然后添加一个按钮。按钮绑定了 click 事件,当按钮被点击时,会调用 handleClick 函数。

5. 使用组件

5.1 在主组件中引入组件

创建好 MyFirstComponent.svelte 组件后,需要在主组件中引入并使用它。Svelte 项目的主组件通常是 src/main.jssrc/App.svelte

打开 src/App.svelte,在其中引入 MyFirstComponent.svelte

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

<template>
    <div>
        <h2>Using My First Component</h2>
        <MyFirstComponent />
    </div>
</template>

<style>
    h2 {
        color: purple;
    }
</style>

在上述代码中,首先通过 import 语句引入了 MyFirstComponent.svelte 组件。然后在模板中使用 <MyFirstComponent /> 标签来渲染该组件。同时,为 h2 标签定义了紫色的文本颜色。

5.2 启动项目查看效果

在项目目录下执行 npm run dev 启动开发服务器,然后在浏览器中访问项目地址。可以看到页面上显示了 MyFirstComponent 组件的内容,包括初始的消息和按钮。点击按钮后,消息会更新为 Button clicked!

6. 组件的属性(Props)

6.1 定义和接收属性

组件之间常常需要传递数据,Svelte 通过属性(Props)来实现这一功能。

修改 MyFirstComponent.svelte,使其能够接收属性:

<script>
    export let initialMessage;
    let message = initialMessage;
    function handleClick() {
        message = 'Button clicked!';
    }
</script>

<style>
    button {
        background - color: green;
        color: white;
        padding: 10px 20px;
        border: none;
        border - radius: 5px;
        cursor: pointer;
    }
</style>

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

在上述代码中,使用 export let initialMessage; 声明了一个属性 initialMessage。然后将 message 初始化为 initialMessage

6.2 传递属性

App.svelte 中传递属性给 MyFirstComponent

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

<template>
    <div>
        <h2>Using My First Component with Props</h2>
        <MyFirstComponent initialMessage="Custom initial message" />
    </div>
</template>

<style>
    h2 {
        color: purple;
    }
</style>

在上述代码中,通过 initialMessage="Custom initial message"MyFirstComponent 传递了一个自定义的初始消息。此时在浏览器中查看,会发现 MyFirstComponent 显示的初始消息变为了传递的自定义消息。

7. 组件的事件

7.1 自定义事件

除了使用 DOM 原生事件,Svelte 组件还可以自定义事件。

MyFirstComponent.svelte 中定义一个自定义事件:

<script>
    import { createEventDispatcher } from'svelte';
    const dispatch = createEventDispatcher();
    export let initialMessage;
    let message = initialMessage;
    function handleClick() {
        message = 'Button clicked!';
        dispatch('custom - event', { newMessage: message });
    }
</script>

<style>
    button {
        background - color: green;
        color: white;
        padding: 10px 20px;
        border: none;
        border - radius: 5px;
        cursor: pointer;
    }
</style>

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

在上述代码中,通过 createEventDispatcher 创建了一个事件分发器 dispatch。当按钮被点击时,除了更新消息,还通过 dispatch('custom - event', { newMessage: message }); 触发了一个名为 custom - event 的自定义事件,并传递了一个包含新消息的对象。

7.2 监听自定义事件

App.svelte 中监听 MyFirstComponent 的自定义事件:

<script>
    import MyFirstComponent from './MyFirstComponent.svelte';
    function handleCustomEvent(event) {
        console.log('Custom event received:', event.detail.newMessage);
    }
</script>

<template>
    <div>
        <h2>Listening to Custom Event</h2>
        <MyFirstComponent initialMessage="Custom initial message" on:custom - event={handleCustomEvent} />
    </div>
</template>

<style>
    h2 {
        color: purple;
    }
</style>

在上述代码中,通过 on:custom - event={handleCustomEvent}MyFirstComponent 绑定了 custom - event 事件的监听器 handleCustomEvent。当 MyFirstComponent 触发 custom - event 事件时,handleCustomEvent 函数会被调用,并将事件对象打印到控制台。在浏览器的开发者工具控制台中,可以看到打印的新消息。

8. 插槽(Slots)

8.1 匿名插槽

插槽允许在组件内部插入自定义内容。Svelte 支持匿名插槽和具名插槽。

首先看匿名插槽的例子,修改 MyFirstComponent.svelte

<script>
    export let initialMessage;
    let message = initialMessage;
    function handleClick() {
        message = 'Button clicked!';
    }
</script>

<style>
    button {
        background - color: green;
        color: white;
        padding: 10px 20px;
        border: none;
        border - radius: 5px;
        cursor: pointer;
    }
</style>

<template>
    <p>{message}</p>
    <button on:click={handleClick}>Click me</button>
    <slot></slot>
</template>

在上述代码中,添加了一个 <slot> 标签。这就是匿名插槽,它允许在使用 MyFirstComponent 时插入任意内容。

App.svelte 中使用匿名插槽:

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

<template>
    <div>
        <h2>Using Anonymous Slot</h2>
        <MyFirstComponent initialMessage="Custom initial message">
            <p>This is some custom content inserted via slot.</p>
        </MyFirstComponent>
    </div>
</template>

<style>
    h2 {
        color: purple;
    }
</style>

在上述代码中,在 MyFirstComponent 标签内部插入了一段自定义的 <p> 标签内容。在浏览器中查看,会发现这段内容显示在 MyFirstComponent 组件的插槽位置。

8.2 具名插槽

具名插槽允许更精确地控制插入内容的位置。

修改 MyFirstComponent.svelte 以使用具名插槽:

<script>
    export let initialMessage;
    let message = initialMessage;
    function handleClick() {
        message = 'Button clicked!';
    }
</script>

<style>
    button {
        background - color: green;
        color: white;
        padding: 10px 20px;
        border: none;
        border - radius: 5px;
        cursor: pointer;
    }
</style>

<template>
    <p>{message}</p>
    <button on:click={handleClick}>Click me</button>
    <slot name="before - button"></slot>
    <slot name="after - button"></slot>
</template>

在上述代码中,定义了两个具名插槽 before - buttonafter - button

App.svelte 中使用具名插槽:

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

<template>
    <div>
        <h2>Using Named Slots</h2>
        <MyFirstComponent initialMessage="Custom initial message">
            <p slot="before - button">This is before the button.</p>
            <p slot="after - button">This is after the button.</p>
        </MyFirstComponent>
    </div>
</template>

<style>
    h2 {
        color: purple;
    }
</style>

在上述代码中,通过 slot="before - button"slot="after - button" 将两段 <p> 标签内容分别插入到 MyFirstComponent 组件的对应具名插槽位置。在浏览器中查看,会看到内容按预期显示在按钮前后。

9. 响应式编程

9.1 基本响应式变量

Svelte 内置了对响应式编程的支持。当一个变量发生变化时,依赖它的 DOM 部分会自动更新。

MyFirstComponent.svelte 中演示基本响应式变量:

<script>
    let count = 0;
    function increment() {
        count++;
    }
</script>

<style>
    button {
        background - color: blue;
        color: white;
        padding: 10px 20px;
        border: none;
        border - radius: 5px;
        cursor: pointer;
    }
</style>

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

在上述代码中,定义了一个变量 count 并初始化为 0。increment 函数会增加 count 的值。在模板中显示 count 的值,并绑定按钮的点击事件到 increment 函数。当点击按钮时,count 会增加,模板中的显示也会自动更新。

9.2 响应式声明

Svelte 还支持使用 $: 进行响应式声明。当响应式声明中的依赖变量发生变化时,声明中的代码会重新执行。

例如,在 MyFirstComponent.svelte 中添加响应式声明:

<script>
    let count = 0;
    let doubledCount;
    $: doubledCount = count * 2;
    function increment() {
        count++;
    }
</script>

<style>
    button {
        background - color: blue;
        color: white;
        padding: 10px 20px;
        border: none;
        border - radius: 5px;
        cursor: pointer;
    }
</style>

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

在上述代码中,使用 $: doubledCount = count * 2; 声明了 doubledCountcount 的两倍。当 count 发生变化时,doubledCount 会自动重新计算,模板中 doubledCount 的显示也会相应更新。

10. 组件的生命周期

10.1 组件的挂载和卸载

Svelte 组件有自己的生命周期方法,包括组件挂载(插入到 DOM 中)和卸载(从 DOM 中移除)时的操作。

MyFirstComponent.svelte 中演示组件的挂载和卸载生命周期方法:

<script>
    import { onMount, onDestroy } from'svelte';
    onMount(() => {
        console.log('Component is mounted.');
    });
    onDestroy(() => {
        console.log('Component is destroyed.');
    });
</script>

<style>
    button {
        background - color: orange;
        color: white;
        padding: 10px 20px;
        border: none;
        border - radius: 5px;
        cursor: pointer;
    }
</style>

<template>
    <p>This is a component with lifecycle methods.</p>
    <button>Some action</button>
</template>

在上述代码中,通过 import { onMount, onDestroy } from'svelte'; 引入了 onMountonDestroy 函数。onMount 函数在组件挂载到 DOM 时会被调用,onDestroy 函数在组件从 DOM 中移除时会被调用。在浏览器的开发者工具控制台中,可以看到组件挂载和卸载时打印的消息。

10.2 响应式更新

除了挂载和卸载,Svelte 还提供了响应式更新的生命周期方法,例如 afterUpdate。它会在组件的 DOM 因为响应式变化而更新后被调用。

MyFirstComponent.svelte 中添加 afterUpdate 示例:

<script>
    import { afterUpdate } from'svelte';
    let count = 0;
    function increment() {
        count++;
    }
    afterUpdate(() => {
        console.log('Component has been updated.');
    });
</script>

<style>
    button {
        background - color: orange;
        color: white;
        padding: 10px 20px;
        border: none;
        border - radius: 5px;
        cursor: pointer;
    }
</style>

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

在上述代码中,通过 import { afterUpdate } from'svelte'; 引入了 afterUpdate 函数。每次 count 变化导致组件 DOM 更新后,afterUpdate 回调函数会被调用,并在控制台打印消息。

通过以上步骤,你已经从零开始学会了 Svelte 的组件化开发,包括创建组件、使用属性、处理事件、插槽应用、响应式编程以及组件生命周期管理等重要方面。随着不断实践,你将能够使用 Svelte 构建出更加复杂和高效的前端应用。