如何学习在下一个 JS 项目中使用 Svelte

2025-06-07

如何学习在下一个 JS 项目中使用 Svelte

在Twitter上关注我,很高兴接受您对主题或改进的建议/Chris

Svelte,我听到这个名字的次数越来越多。

它应该会改变一切

我说真的,另一个 SPA 框架?

是的,这就是 IT。它可能会颠覆 Angular、React 和 Svelte 三大巨头之一。

当然,我有点怀疑。它肯定会随着时间的推移而好转,还是我们已经到了这个地步了?

让我们来看看 :)

那么,什么会促使我们抛弃当前使用的框架,或者添加新的框架呢?
嗯,我做的第一件事就是查看 GitHub,看看这个框架有多流行?

看看大约3万次启动,其中9.5万次被使用。我觉得这相当不错。

这事儿是凭空而来的吗?

经过一些研究表明它是在 2016 年创建的,目前是第 3 版。所以它已经存在了,这很好。

假设我们选择 Svelte 作为我们下一个项目的测试工具,那么我们应该对它抱有怎样的期望才能认真对待它呢?

好吧,这是我的必备清单,你的清单可能会有所不同:

  • 以组件为中心,我的意思是当今所有伟大的框架都是以组件为中心的
  • 路由,是的,我需要路由
  • 测试,如果没有测试库,我不会编写一堆代码
  • 表格,听起来很无聊,是的,需要有适当的支持来将数据收集到表格中。
  • 数据绑定,某种数据绑定就是我们想要的
  • 工具方面,我希望有一个命令行界面 (CLI),这样我就可以搭建项目、运行我的应用,如果能支持热加载就更好了。此外,我还希望有一个简便的方法来打包我的应用。

好的,我们列出了一些需要研究的需求/功能。但首先,我们来谈谈 Svelte 是如何运作的。

什么

Svelte 是一种构建用户界面的全新方法。React 和 Vue 等传统框架的大部分工作都在浏览器中完成,而 Svelte 则将这些工作转移到构建应用时的编译步骤中。

好的,编译时会发生很多事情。您还能告诉我什么?

Svelte 不使用虚拟 DOM 差异等技术,而是编写代码,在应用程序状态发生变化时精确更新 DOM。

好吧,所以没有虚拟 DOM。不过,外科手术式的更新,听起来挺奇葩的。

Svelte 是一个组件框架,就像 React、Vue 和 Angular 一样。

好的,我们得到了组件

不过,两者之间还是有区别的。上述框架使用声明式状态驱动代码,需要将其转换为 DOM 操作。这会带来帧率和垃圾回收的开销。

我猜 Svelte 以某种方式避免了这种情况?

Svelte 则不同,它在构建时运行。它们的组件被转换成命令式代码,从而提供了出色的性能。

听起来很有希望

Svelte 目前处于第 3 版,经历了重大变化,以确保开发人员体验良好,并清除了大部分样板代码。

开发人员经验,是的,必须具备。

资源

以下是我认为您应该在阅读本文时或之后查看的一些资源。

成分

Svelte 就像 Vue、React、Angular 这三大 SPA 一样,都是面向组件的。那么,我们来聊聊 Svelte 中的组件。

Svelte 中的组件存储在一个单独的文件中,该文件以 结尾.svelte。它包含一个script包含代码的部分、一个style包含样式的部分和一个标记部分。

一个简单的组件看起来像这样:

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

<h1>Hello {name}</h1>
Enter fullscreen mode Exit fullscreen mode

就是这样?

是的,没什么变化。然而,看看最终的代码,却发现情况并非如此:

/* App.svelte generated by Svelte v3.16.7 */
import {
  SvelteComponent,
  detach,
  element,
  init,
  insert,
  noop,
  safe_not_equal
} from "svelte/internal";

function create_fragment(ctx) {
  let h1;

  return {
    c() {
      h1 = element("h1");
      h1.textContent = "Hello world!";
    },
    m(target, anchor) {
      insert(target, h1, anchor);
    },
    p: noop,
    i: noop,
    o: noop,
    d(detaching) {
      if (detaching) detach(h1);
    }
  };
}

class App extends SvelteComponent {
  constructor(options) {
    super();
    init(this, options, null, create_fragment, safe_not_equal, {});
  }
}

export default App;
Enter fullscreen mode Exit fullscreen mode

已经很多了。好消息是,我们不必再写这些了。

插值

请注意我们是如何使用插值的{}

这也可以用于 HTML 属性,如下所示:

<script>
  let src = 'tutorial/image.gif';
</script>

<img src={src}>
Enter fullscreen mode Exit fullscreen mode

造型

除了将代码放在script标签中之外,我们还将样式放在style标签中,如下所示:

<style>
  p {
    color: purple;
    font-family: 'Comic Sans MS', cursive;
    font-size: 2em;
  }
</style>
Enter fullscreen mode Exit fullscreen mode

最好的部分是它的范围限定在组件内 - 它不会泄漏。

 导入组件

import您可以使用如下关键字导入组件:

<script>
  import Nested from './Nested.svelte';
</script>
Enter fullscreen mode Exit fullscreen mode

像这样使用它:

// App.svelte

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

<p>Some text</p>
<Nested />
Enter fullscreen mode Exit fullscreen mode

是不是很简单?你几乎看不到框架,只有 HTML、CSS 和 JS。

 你的第一个项目

理论讲得够多了。让我们开始构建一些东西吧。使用 Svelte 构建任何东西最简单的方法是使用以下命令搭建一个新的 Svelte 项目:

npx degit sveltejs/template <name of project>
Enter fullscreen mode Exit fullscreen mode

然后运行:

npm install
Enter fullscreen mode Exit fullscreen mode

其次是

npm run dev
Enter fullscreen mode Exit fullscreen mode

您应该看到以下内容:

我们好像有LiveReload,很好!

它已在端口 上启动并运行5000。我们去检查一下吧!

就是这样。你好,Svelte

那么实时重新加载呢?我们应该能够进入代码,修改一个变量,然后在浏览器中看到它的变化,而无需启动/停止应用程序。

浏览器现在显示:

太棒了!这可行。是啊,我有点被宠坏了,想要让实时重新加载功能正常工作。我记得我刚开始用 JS 的时候没有这个。

幸好现在这是必须的:)

构建我们的第一个组件

好的,我们有一个项目,让我们继续创建我们的第一个组件并学习一些技巧,例如如何渲染数据以及如何使用属性或道具。

让我们通过创建文件来创建一个 CV 组件CV.svelte并赋予它以下内容:

<script>
  let title = 'chris'
</script>

<h1>{title}</h1>
Enter fullscreen mode Exit fullscreen mode

现在打开,App.svelte因为我们需要通过以下方式使用这个组件:

  • 导入,我们需要导入组件才能使用它
  • 将其添加到标记中

您需要以下行进行导入,请将其放在script标签内:

import CV from './CV.svelte';
Enter fullscreen mode Exit fullscreen mode

要使用它,我们需要将它放在标记中,如下所示:

<main>
  <CV />
</main>
Enter fullscreen mode Exit fullscreen mode

您现在应该在浏览器中看到以下内容:

道具

接下来,我们想学习如何向组件发送数据。我们使用 Svelte 中的属性(props)来实现。那么如何使用它们呢?

很简单,使用关键字export

返回到您的CV.svelte文件并添加关键字,export如下所示:

<script>
  export let title = 'chris'
</script>
Enter fullscreen mode Exit fullscreen mode

现在我们可以从外部主动设置title属性了。让我们打开App.svelte文件并执行此操作。

我们在script部分中定义一个新对象:

let person = {
  name: 'chris'
}
Enter fullscreen mode Exit fullscreen mode

然后我们在标记部分引用它,如下所示:

<main>
  <CV title={person.name} />
</main>
Enter fullscreen mode Exit fullscreen mode

这似乎仍然在我们的浏览器中起作用,太棒了:)

使用 for 循环

当然,我们希望能够渲染比字符串或数字更复杂的数据。列表怎么样?我们可以通过使用如下结构轻松实现:

{#each skills as skill}
<div>Name: {skill.name}, Level: {skill.level}</div>
{/each}
Enter fullscreen mode Exit fullscreen mode

skills上面是一个列表,skill是我们为列表中的特定项目指定的名称。我们需要执行以下操作才能使所有这些正常工作:

  1. 更新我们的人员对象以包含技能列表
  2. 更改我们的输入属性以获取对象
  3. 将for 循环渲染代码添加到我们的 CV 组件

让我们开始App.svelte并更新我们的数据对象,如下所示:

let person = {
  name: 'chris',
  skills: [
    {
      name: 'Svelte',
      level: 5
    },
    {
      name: 'JavaScript',
      level: 5
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

现在让我们发送整个对象,而不仅仅是标题。因此,我们将标记更改为App.svelte

<main>
  <CV person={person} />
</main>
Enter fullscreen mode Exit fullscreen mode

现在我们打开CV.svelte并将其更改为以下内容:

<script>
  export let person;
</script>

<h1>{person.name}</h1>
{#each person.skills as skill}
  <div>Skill: {skill.name} Level: {skill.level}</div>
{/each}
Enter fullscreen mode Exit fullscreen mode

现在看起来应该是这样的:

使用条件

好的,看起来好多了,但我们应该学习如何使用 IF、ELSE 之类的语句。让我们处理skills数据,并根据级别进行不同的渲染。

假设我们想要输出REALLY GOOD级别是否为 5
以及GOOD级别是否为 4。我们可以使用 Svelte 中的条件结构来解决这个问题,如下所示:

{#if condition}
// render something
{:else if otherCondition}
// render something else
{:else}
// render
{/if}
Enter fullscreen mode Exit fullscreen mode

 逻辑

我们可以使用模板逻辑来表达 IF 和 FOR 循环,像这样

如果

{#if condition}
// markup
{/if}
Enter fullscreen mode Exit fullscreen mode

以下登录组件就是一个例子:

<script>
  let user = { loggedIn: false };

  function toggle() {
    user.loggedIn = !user.loggedIn;
  }
</script>

{#if user.loggedIn}
<button on:click={toggle}>
  Log out
</button>
{/if}

{#if !user.loggedIn}
<button on:click={toggle}>
  Log in
</button>
{/if}

Enter fullscreen mode Exit fullscreen mode

别的

我们可以使用 ELSE 来改进上述代码。它的语法位于{:else}a 内部{#if}。以下是示例:

{#if user.loggedIn}
<button on:click={toggle}>
  Log out
</button>
{:else}
<button on:click={toggle}>
  Log in
</button>
{/if}
Enter fullscreen mode Exit fullscreen mode

否则,如果

我们还可以使用 ELSE IF 来表达更多布尔开关逻辑。就像 ELSE 一样,它使用:类似 的{:else if condition}。更长的示例如下所示:

{#if x > 10}
<p>{x} is greater than 10</p>
{:else if 5 > x}
<p>{x} is less than 5</p>
{:else}
<p>{x} is between 5 and 10</p>
{/if}
Enter fullscreen mode Exit fullscreen mode

让我们在skills列表中添加一个条目{ name: 'Photoshop', level: 3 }并调整组件CV.svelte使其看起来像这样:

<script>
  export let person;
</script>

<h1>{person.name}</h1>
{#each person.skills as skill}
  <div>Skill: {skill.name} 
     Level: {skill.level}
    {#if skill.level == 5}
    REALLY GOOD
    {:else if skill.level == 4}
    GOOD
    {:else}
    DECENT
    {/if}
  </div>
{/each}
Enter fullscreen mode Exit fullscreen mode

好的,很好,我们也知道如何处理条件。

添加 HTTP

Svelte 中非常酷的一点是它能够非常轻松地处理 HTTP 端点并渲染结果。为此,我们将使用一个名为 的模板构造await

让我们来谈谈我最喜欢的 SWAPI 端点之一——星球大战 API。为了能够使用我们的await构造,我们需要按照以下方式进行:

  • 构建我们的 Promise,这是我们对端点进行实际调用的地方
  • 定义我们的异步模板,在这里我们将设置标记,以便我们可以在数据到达时呈现数据,并且如果出现问题,我们也有能力进行呈现

构建我们的承诺

让我们在组件中定义一个函数,如下所示:

<script>
  let promise = getData();

   async function getData() {
    const response = await fetch('https://swapi.co/api/people');
    const json = await response.json();
    return json.results;
  }  
</script>
Enter fullscreen mode Exit fullscreen mode

定义我们的异步模板

它的模板如下所示:

{#await promise}
 <p>...loading</p>
 {:then data}
 <p>Here is your data {data}</p>
   {#each data as row} 
     <div>{row.name}</div>
   {/each}
 {:catch error}
 <p>Something went wrong {error.message}</p>
{/await}
Enter fullscreen mode Exit fullscreen mode

如上所示,我们指定了promise变量作为需要等待的对象。我们还指定了{:then data}获取的数据应该渲染到哪里,并将该数据命名为data。最后,我们用 指定了错误渲染到哪里{:catch error}

我们将所有这些添加到一个单独的组件中HttpDemo.svelte,并使其看起来像这样:

<!-- HttpDemo.svelte -->

<script>
  let promise = getData();

  async function getData() {
    const response = await fetch('https://swapi.co/api/people');
    const json = await response.json();
    return json.results;
  }
</script>
<style>
  .row {
    margin: 10px;
    box-shadow: 0 0 5px gray;
    padding: 10px 20px;
  }

  .error {
    background: lightcoral;
    border: solid 1px red;
    padding: 10px 20px;
  }
</style>
{#await promise}
 <p>...loading</p>
 {:then data}
 <div>
   {#each data as row}
     <div class="row">{row.name}</div>
   {/each}
</div>
 {:catch error}
 <div class="error">
   Something went wrong {error.message}
 </div>
{/await}
Enter fullscreen mode Exit fullscreen mode

运行该应用程序你应该看到类似这样的内容:

 活动

好的,现在我们对如何使用不同的指令、如何渲染数据、如何处理 HTTP 等有了更多的了解。那么事件呢?我们感兴趣的有两种类型的事件:

  1. DOM 事件,通常发生在点击按钮、移动鼠标​​、滚动等操作时。我们可以为这些事件分配一个处理程序
  2. 自定义事件,这些是我们创建并可以调度的事件。就像 DOM 事件一样,我们可以设置处理程序来捕获这些事件。

那么,我们如何在应用程序中学习这些事件类型呢?让我们尝试通过添加数据来改进我们的简历。

添加技能

好的,为了能够添加技能,我们需要两样东西

  1. 输入字段,这些字段应该捕获技能的名称和你当前的技能级别
  2. 一个按钮,这将引发一个事件,最终将技能保存到简历中
  3. 广播,我们需要告诉我们的组件添加了一项新技能。毕竟父组件是存放简历数据的组件,所以我们需要在那里进行更改。

输入字段

让我们添加以下标记

<h1>{person.name}</h1>

<h2>Add skill</h2>
<div>
  <input bind:value={newSkill} placeholder="skill name">
  <input bind:value={newSkillLevel} type="number" min="1" max="5" />
  <button on:click={saveSkill} >Save</button>
 </div>
Enter fullscreen mode Exit fullscreen mode

一个按钮

现在我们需要在部分中添加以下代码script

  let newSkill = '';
  let newSkillLevel = 1;

  function saveSkill() {
    // TODO save skill
    console.log('saving skill', newSkill, newSkillLevel);
  }
Enter fullscreen mode Exit fullscreen mode

播送

现在我们需要实现该方法saveSkill()。它需要引发父组件可以监听的自定义事件。我们在 Svelte 中使用createEventDispatcher如下方式引发自定义事件:


function sayHello() {
  dispatch('message', {
    text: 'Hello!'
  });
}
Enter fullscreen mode Exit fullscreen mode

让我们将其应用到我们当前的代码中:

<script>
  import { createEventDispatcher } from 'svelte';

  export let person;
  const dispatch = createEventDispatcher();

  let newSkill = '';
  let newSkillLevel = 1;

  function saveSkill() {
    dispatch('newSkill', {
      skill: newSkill,
      level: newSkillLevel
    });
  }
</script>
Enter fullscreen mode Exit fullscreen mode

好的,我们知道如何向上发送消息,我们如何捕获它?

很简单,我们使用on:<nameOfCustomMessage>并为其分配一个处理程序。现在打开App.svelte并将以下代码添加到我们的标记和脚本部分:

<CV person={person} on:newSkill={handleNewSkill} />
Enter fullscreen mode Exit fullscreen mode

对于我们的script部分:

function handleNewSkill(newSkill) {
  console.log('new skill', newSkill);
}
Enter fullscreen mode Exit fullscreen mode

运行此程序时,您应该在控制台中看到以下内容:

请注意上面我们的消息在detail属性中是怎样的。

让我们完成代码,以便我们将新技能分配给我们的person属性并确保 UI 按预期工作。

function handleNewSkill(newSkill) {
  const { detail: { skill, level } } = newSkill;
  person.skills = [...person.skills, { name: skill, level }];
}
Enter fullscreen mode Exit fullscreen mode

我们的用户界面如下:

概括

我以为就此打住。这篇文章已经够长了。我计划在 Svelte 上写更多篇幅,我认为你一次就能消化这么多内容。下一篇我们来讨论如何使用路由和测试,因为这些也包含在内。

文章来源:https://dev.to/itnext/how-you-can-learn-to-use-svelte-for-your-next-js-project-3k8h
PREV
⚛️ 在 React 中应用策略模式(第二部分)
NEXT
通过构建一个极简电商购物应用来了解 React Context API 的工作原理