发布于 2026-01-06 0 阅读
0

Svelte教程笔记

Svelte教程笔记

这是我在学习Svelte 教程时记下的笔记。

或许对某些人有用,但首先,这是写给自己的笔记 :)

1. 引言

创建一个新的 Svelte 项目

https://svelte.dev/blog/svelte-for-new-developers

npx degit sveltejs/template new-project-name

VS Code

安装以下扩展程序

  1. 苗条
  2. Svelte 智能感知

2. 反应活性

a. 作业

https://svelte.dev/tutorial/reactive-assignments

on:click on看起来像一个指令,它click是事件名称。

状态是响应式的,script标签下的闭包会在状态值改变时重新渲染。

<script>
    let count = 0;

    function handleClick() {
        count++;
    }
</script>

<button on:click={handleClick}>
    Clicked {count} {count === 1 ? 'time' : 'times'}
</button>

b. 声明

https://svelte.dev/tutorial/reactive-declarations

计算/派生状态需要使用特殊语法进行声明$:

let count = 0;
$: doubled = count * 2;

当需要多次访问时非常有用。您可以改用其他方式,

不是到处都用。{count * 2}{doubled}

c. 声明

https://svelte.dev/tutorial/reactive-statements

$:不仅限于表达式(响应式值),也包括语句。

<script>
    let count = 0;

    $: console.log(`the count is {count}`);

    $: if (count >= 10) {
        alert(`count is too high!`)
        count = 9;
    }

    function handleClick() {
        count += 1;
    }
</script>

<button on:click={handleClick}>
    Clicked {count} {count === 1 ? 'time' : 'times'}
</button>

d. 更新数组和对象

https://svelte.dev/tutorial/updating-arrays-and-objects

一个简单的经验法则:更新后的变量名必须出现在赋值语句的左侧。

或者像在 React 中那样,赋予一个新的引用。

// Instead of this
function addNumber() {
  numbers.push(numbers.length + 1);
  numbers = numbers
}

// Do this
function addNumber() {
  numbers = [...numbers, numbers.length + 1]
}

3.道具

a. 声明属性

https://svelte.dev/tutorial/declaring-props

用于将数据传递给其他组件。这与 React 中的概念相同。

在 React 中,组件接收数据props,但在 Svelte 中,你需要导出变量。

Nested.svelte

<script>
  export let answer;
</script>
<p>The answer is {answer}</p>

App.svelte导入Nested组件并按如下方式传递答案。

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

<Nested answer={42}>

b. 默认值

https://svelte.dev/tutorial/default-values

您可以在声明期间设置默认属性值。

Nested.svelte

<script>
  export let answer = 'is unknown!';
</script>
<p>The answer is {answer}</p>

如果没有向Nestedlike传递 props <Nested>,则使用默认值。

c. 展开道具

https://svelte.dev/tutorial/spread-props

就像在 React 中一样,你可以使用对象展开运算符传递多个 props。

<Info {...pkg}>

4. 逻辑

a. 如果块

https://svelte.dev/tutorial/if-blocks

该标记仅在 Svelte 中可用,在 HTML 中不可用。

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

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

b. 否则会阻塞

https://svelte.dev/tutorial/else-blocks

互斥条件可以使用{:else}

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

c. 否则语句块

https://svelte.dev/tutorial/else-if-blocks

可以通过以下方式检查其他条件{:else if condition}

{#if x > 10}
  <p>{x} is greater than 10!</p>
{:else if x < 5 }
  <p>{x} is less than 5
{:else}
  <p>{x} is 'teween 5 and 10</p>
{/if}

d. 每个方块

https://svelte.dev/tutorial/each-blocks

你可以使用以下方式迭代可迭代对象{#each iterable as alias, index}

<ul>
{#each cats as cat, index}
  <li>{index + 1}th cat is {cat.name}</li>
{/each}
</ul>

别名可以像这样解构:

{#each cats as {name, id, age}, index}
  <li>{index + 1}th cat is {name} and is {age} years old</li>
{/each}

e. 为每个块添加键

https://svelte.dev/tutorial/keyed-each-blocks

在 React 中,创建可迭代元素需要key为每个元素创建一个迭代器。

例如)

{things.map(thing => <li key={thing.id}>{thing.color}</li>)}

在 Svelte 中,您需要在标记中指定键。

{#each things as thing (thing.id)}
  <li>{thing.color}</li>
{/each}

或者你可以进行解构thing

{#each things as {id, color} (id)}
    <Thing current={color}/>
{/each}

f. 等待块

https://svelte.dev/tutorial/await-blocks

awaitSvelte 标记语言提供了一种处理Promise的方法。

由于 Svelte 只会获取最新的 Promise,因此可以自动处理竞态条件。

{#await promise}
  <p>Loading...</p>
{:then number}
  <p>The value is {number}<p>
{:catch error}
  <p class="error">{error.message}</p>
{/await}

您可以选择不显示中间的“加载中”消息,并等待 Promise 解析完成。

{#await promise then number}
  <p>The value is {number}<p>
{/await}

这比 React 中的抽象要清晰得多,在 React 中,需要使用useEffect异步方法解析 Promise 并设置状态。

5. 事件

a. DOM 事件

https://svelte.dev/tutorial/dom-events

使用on:指令,后跟 DOM 事件名称。

例如)鼠标移动

<script>
    let m = { x: 0, y: 0 };

    function handleMousemove(event) {
        m.x = event.clientX;
        m.y = event.clientY;
    }
</script>

<style>
    div { width: 100%; height: 100%; }
</style>

<div on:mousemove={handleMousemove}>
    The mouse position is {m.x} x {m.y}
</div>

b. 内联处理程序

https://svelte.dev/tutorial/inline-handlers

⚠ 与 React 不同,内联事件处理程序不会导致任何性能问题,因为 Svelte 知道如何进行优化。

相反,

<div on:mousemove={handleMousemove}>
    The mouse position is {m.x} x {m.y}
</div>

您可以handleMousemove像下面这样内联插入。

<div on:mousemove={e => m = {x: e.clientX, y: e.clientY}}>
    The mouse position is {m.x} x {m.y}
</div>

或者,在某些编辑器中,为了实现语法高亮显示,可以将内联方法用引号括起来。

<div on:mousemove="{e => m = {x: e.clientX, y: e.clientY}}">
    The mouse position is {m.x} x {m.y}
</div>

c. 事件修饰符

https://svelte.dev/tutorial/event-modifiers

你可以使用修饰符来“装饰”(我的理解)事件,例如:

  • once运行一次处理程序
  • prevetnDefaultevent.preventDefault()在调用处理程序之前
  • stopPropagation停止event.stopPropagation()事件气泡/捕获
  • passive:用于触控/滚轮滚动性能(谷歌将其添加为非标准,但得到了广泛支持)
  • capture默认情况下,DOM 事件会向上冒泡。此操作会将其反转capture(请参阅 MDN Event.eventPhase)。
  • selfevent.target === current element

例如)用于once仅在按钮上运行一次事件处理程序

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

修饰符可以串联使用。on:click|once|capture|preventDefault

handleClick无论你按多少次按钮,都只会调用一次。

⚠ 空格很重要!下面的代码无效,因为句点之间有空格|

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

d. 组件事件

https://svelte.dev/tutorial/component-events

与原生JS中的自定义事件分发(需要将自定义数据作为detail属性传递)不同,

// add an appropriate event listener
obj.addEventListener("cat", function(e) { process(e.detail) });

// create and dispatch the event
let event = new CustomEvent("cat", {
  👇
  detail: {
    hazcheeseburger: true
  }
});
obj.dispatchEvent(event);

你发送一个包含数据的事件,它将event.detail自动作为一部分提供。

Inner.svelte

<script>
    import {createEventDispatcher} from 'svelte'

    const dispatch = createEventDispatcher()

    function sayHello() {
    // NOT THIS!
    // dispatch('message', {detail: {text: 'hi!'}})
    // But pass the data as it is
        dispatch('message', { text: 'Hello!' });
    }
</script>

<button on:click={sayHello}>
    Click to say hello
</button>

然后,您可以像这样使用该组件并订阅事件message

App.svelte

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

    function handleMessage(event) {
    // Access "text" via 👇 event.detail 
        alert(event.detail.text);
    }
</script>

<Inner on:message={handleMessage}/>

这种模式与 React 不同,React 中内部组件接收一个“事件处理程序”作为函数并调用它,而不是声明一个事件。

const App = () => <Inner onMessage={handleMessage}>
const Inner = ({onMessage}) => <button onClick={onMessage}>Click</button>

看来在 Svelte 中,事件处理程序是使用原生 JavaScript 的CustomEvent接口声明的。

e. 事件转发

https://svelte.dev/tutorial/event-forwarding

DOM 事件会向上冒泡,而 Svelte 事件则不会。可以通过在每一层创建事件分发器来实现显式的事件转发。

Svelte 可以通过快捷方式转发事件,只需指定on:eventname指令而不指定值即可。

<Inner on:message>

然后所有on:message事件处理程序都将被转发并提供给调用组件。

注意:这有点难理解,需要稍后再来研究。

f. DOM 事件转发

https://svelte.dev/tutorial/dom-event-forwarding

Svelte 要求你明确决定是否公开某个事件。

当内部组件中有多个元素暴露同一个事件时,例如两个按钮on:click

CustomButton.svelte

<button id="b1" on:click>
    Click me
</button>

<button id="b2" on:click>
    Click me2
</button>

然后你可以通过检查来判断是哪颗子弹射出的。event.target

App.svelte

<script>
  import CustomButton from './CustomButton.svelte'

  function handleClick(event) {
    console.log(`e =>`, event.target)
  }
</script>

<CustomButton on:click={handleClick}> />

点击自定义按钮#b1#b2结果如下:

e => <button id="b1">Click me</button>e => <button id="b2">Click me2</button>

6. 装订

a. 文本输入

https://svelte.dev/tutorial/text-inputs

有点像双向绑定,元素的变化会更新状态和当前状态。

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

<input bind:value={name}>

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

更新值input会同时更新name状态和输入值。

b. 数值输入

https://svelte.dev/tutorial/numeric-inputs

电池已包含

Svelte 会自动将类型为number& 的输入转换range为数值。

而 React 则需要显式转换,因为它基于底层技术。

c. 复选框输入

https://svelte.dev/tutorial/checkbox-inputs

复选框输入类型值绑定到bind:checked而不是bind:value

<script>
    let isChecked = false
</script>
<input type="checkbox" bind:checked={isChecked}>

d. 小组输入

https://svelte.dev/tutorial/group-inputs

在原生 JavaScript 中,您可以使用 ` name<select>` 来对相关的复选框和单选按钮进行分组。MDN

参考:<input type="radio">

<form>
                                            👇
    <input type="radio" name="scoops" value="1">
    <input type="radio" name="scoops" value="2">
    <input type="radio" name="scoops" value="3">
</form>

但在 Svelte 中,您可以使用指令绑定组bind:group

<form>
                                            👇
    <input type="radio" bind:group="scoops" value="1">
    <input type="radio" bind:group="scoops" value="2">
    <input type="radio" bind:group="scoops" value="3">
</form>

当绑定到单选按钮组时,绑定的值是一个值;但对于复选框,绑定的值是一个数组。

<script>
    let scoops = 1;
    let flavours = [];
</script>

<!-- Radio `scopes` bound to a single value -->
<label>
    <input type=radio bind:group={scoops} value={1}>
    One scoop
</label>
<label>
    <input type=radio bind:group={scoops} value={2}>
    Two scoops
</label>
<label>
    <input type=radio bind:group={scoops} value={3}>
    Three scoops
</label>

<!-- Checkbox group value, `favlours` is an array -->
<label>
    <input type=checkbox bind:group={flavours} value="Cookies and cream">
    Cookies and cream
</label>
<label>
    <input type=checkbox bind:group={flavours} value="Mint choc chip">
    Mint choc chip
</label>
<label>
    <input type=checkbox bind:group={flavours} value="Raspberry ripple">
    Raspberry ripple
</label>

e. 文本区域输入

https://svelte.dev/tutorial/textarea-inputs

与此相同<input type="text">。您可以使用绑定值bind:value={value}。如果值变量名匹配value,则可以省略赋值语句,例如:

<textarea bind:value></textarea>

f. 选择绑定

https://svelte.dev/tutorial/select-bindings

与 Textarea 类似,如果变量名为. ,则可以使用bind:value={value}它并省略赋值。bind:valuevalue

<script>
let value;
let answer = ""
const questions = [
    {id: 1, 'question #1'},
    {id: 2, 'question #2'},
    {id: 3, 'question #3'},
]
</script>

<!-- this works too 👇 -->
<!-- <select bind:value={value} on:change="{() => answer = ""}"> -->
<select bind:value on:change="{() => answer = ""}">
    {#each questions as question}
        <option value={question}>{question.text}</option>
    {/each}
</select>

<input bind:value={answer}>

g. 选择多个

https://svelte.dev/tutorial/multiple-select-bindings

我之前已经在https://svelte.dev/tutorial/group-inputsd. Group inputs中提到过这一点了。

使用指令绑定到 select 元素multiple会将值设置为数组。

flavours是一个数组。

<select multiple bind:value={flavours}>
    {#each menu as flavour}
        <option value={flavour}>
            {flavour}
        </option>
    {/each}
</select>

h. 可编辑内容绑定

https://svelte.dev/tutorial/contenteditable-bindings

你可以绑定到其中任何一个textContentinnerHTML

<div
    contenteditable="true"
    bind:innerHTML={html}
></div>
<!-- or -->
<div
    contenteditable="true"
    bind:textContent={html}
></div>

了解一下&和之间的区别textContentinnerHTML

,以及为什么应该考虑使用textContent而不是innerHTML

i. 每个块绑定

https://svelte.dev/tutorial/each-block-bindings

如果你打算使用不可变数据(React 风格),就不要用这个。

熟悉命令式编程风格?那就用这个。

j. 中间元素

https://svelte.dev/tutorial/media-elements

使用.video/audiorequestAnimationFrame

k. 尺寸

https://svelte.dev/tutorial/dimensions

每个块级元素,例如div,,section都有以下属性的绑定article

一、这

https://svelte.dev/tutorial/bind-this

bind:this={variable}返回对已渲染元素的引用。该引用在组件挂载之前

variable一直有效。 请使用onMount生命周期方法来引用该变量。undefined

注意:这看起来像是ref在 React 中。

m. 组件绑定

https://svelte.dev/tutorial/component-bindings

如前所述,您可以bind:value为自定义组件提供双向绑定。

子组件的更改将在父元素中生效。

Keypad.svelte

<script>
export let value;
</script>
...

假设在App.svelte

<script>
    import Keypad from './Keypad.svelte'

    let pin;

    const handleSubmit = () => console.log(`pin => ${pin}`)
</script>

<input bind:value={pin} />
<Keypad bind:value={pin} on:submit={handleSubmit}>

你可以绑定到Keypadbind:value={pin}。它既可以作为组件的输入,也可以作为输出Keypad

可以通过更改其中的值来演示它的功能<input bind:value={pin} />

太棒了!非常方便。但是要小心,因为你可能会搞不清状态流向。

在 React 中,需要传递一个回调函数,以便在子元素值发生变化时调用该函数,父元素将通过回调函数更新状态。

App.jsx

function App() {
    const [pin, setPin] = React.useState(null)

    return <Keypad onChange={setPin} />
}

7. 生命周期

a. onMount

https://svelte.dev/tutorial/onmount

它类似于componentDidMountuseEffect的混合,因为它在组件挂载时调用,并通过从中返回的回调函数进行清理(这就是useEffect 进行清理的方式)。

此外,componentDidMount它既可以调用异步方法async,也不useEffect可以调用异步方法。

这是fetchReact 中推荐的调用方式,onMount通常情况下,人们应该在这里发出网络请求。

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

    onMount(async () => {
        const response = await fetch('https://www...');
        photos = await response.json();

        return () => {
            // clean up resources here
        };
    });
</script>

b. onDestroy

https://svelte.dev/tutorial/ondestroy

onDestroy类似于 React 的componentWillUnmount。使用它在组件卸载阶段清理资源。

<script>
    import { onDestroy } from 'svelte'

    let seconds = 1;
    const id = setInterval(() => seconds++, 1000)

    onDestroy(() => void clearInterval(id))
</script>

c. 更新前和更新后

https://svelte.dev/tutorial/update

流动方式如下:

beforeUpdate-> onMount-> beforeUpdate-> 状态变化 -> afterUpdate->onDestroy

由于beforeUpdate运行在之前onMount,因此需要检查元素是否存在。

d. 蜱虫

https://svelte.dev/tutorial/tick

为了绕过批量处理(状态更新、DOM 更新等)

<script>
    import { tick } from 'svelte'
</script>

8. 商店

a. 可写存储

https://svelte.dev/tutorial/writable-stores

Svelte 内置电池,并附带全局状态管理库。

svelte/store具有writable创建全局状态的方法。

store.js

import { writable } from 'svelte/store'

export const count = writable(0)

然后就可以导入countstore.js用于读取、更新或设置值。

  1. 通过订阅读取数据writable会返回一个状态,你可以subscribe()查看该状态的值是否发生变化。这是一个高阶函数(HoF),它会返回一个取消订阅的函数。这与Redux store 的 subscribe 方法返回 unsubscribe 方法的方式相同。我猜测你需要正常调用unsubscribeunsubscribe方法onDestroy来清理数据。
<script>
    import { onDestroy } from 'svelte'
    import { count } from './store'

    let countValue;
    const unsubscribe = count.subscribe(value => { countValue = value });
    // Clean up after your business!
    onDestroy(unsubscribe);
</script>
  1. 更新状态 -writable返回一个状态,您可以update为其赋值 - 它需要一个回调函数,该回调函数会接收要更新的当前值。
<script>
    import { count } from './store.js'
    const incrementCount = () => count.update(currentValue => currentValue + 1)
</script>

<button on:click={incrementCount}>Increment Count by One/button>
  1. 设置状态(便捷的更新方法)——set该方法看起来像是一个便捷方法update,因为您可以直接设置一个值而无需回调函数。
<script>
    import { count } from './store.js'
    const reset = () => count.set(0)
</script>

<button on:click={reset}>Reset Count</button>

b. 自动订阅

https://svelte.dev/tutorial/auto-subscriptions

Svelte 还提供了另一种便捷的方式来订阅全局状态变化。

通过$在变量前加上前缀,Svelte 会自动处理订阅和取消订阅的操作。

与其使用冗长的取消/订阅命令count

<script>
    import { onDestroy } from 'svelte'
    import { count } from './store'

    let countValue;
    const unsubscribe = count.subscribe(value => { countValue = value });
    // Clean up after your business!
    onDestroy(unsubscribe);
</script>

<p>Count value is {countValue}</p>

你可以简单地count加上$前缀$count

<script>
    import { onDestroy } from 'svelte'
    import { count } from './store'
</script>

<p>Count value is {$count}</p>

请务必阅读链接页面中的注释。

c. 可读商店

https://svelte.dev/tutorial/readable-stores

可读存储提供的是只读存储,可以初始化但不能更新。

这看起来类似于useEffect“当最后一个订阅者取消订阅时”调用返回函数。

store.js

import { readable } from 'svelte';

const initialValue = new Date();
const valueUpdator = set => {
    const id = setInterval(() => set(new Date()), 1000);

    // called when the last subscriber unsubscribes.
    return () => clearInterval(id);
}

export const time = readable(initialValue, valueUpdator);

与 store 一样,你可以像在另一个文件中一样,通过前缀wriable来引用它。$$time

d. 衍生商店

教程中回调函数time使用了$类似前缀。$time

自动订阅教程指出:

任何以 $ 开头的名称都被视为指向存储值。它实际上是一个保留字符——Svelte 会阻止你声明带有 $ 前缀的变量。

但我尝试去掉$前缀,如下所示,仍然有效。

export const elapsed = derived(
    time,
    t => Math.round((t - start) / 1000)
);

不确定是否$需要。我在 Reddit 上提问了。https

://www.reddit.com/r/sveltejs/comments/hblmxa/question_derived_callback_in_tutorial_uses_a/

e. 定制商店

https://svelte.dev/tutorial/custom-stores

可以通过实现方法来创建自定义存储subscribe

本教程使用wriable`s`subscribe来暴露接口,但并未展示如何自行实现。

f. 商店绑定

https://svelte.dev/tutorial/store-bindings

以前缀引用的存储值$可以像本地状态一样进行绑定。

<script>
import { name } from './store.js';
</script>

<input bind:value={$name}>

输入内容后,系统将更新$name自身及其所有依赖项。

9. 运动

a. 过渡动画

https://svelte.dev/tutorial/tweened

Svelte 内置了运动库,无需安装第三方库。

而在 React 中,你需要使用 ` react-springMotion`、`MotionById`react-motion等。

b. 春季

https://svelte.dev/tutorial/spring

tweened对于经常更改的值,请使用此方法代替。

10. 过渡

a. 过渡指令

https://svelte.dev/tutorial/transition

另一种在 JavaScript 中实现过渡效果的便捷方法。

根据 Chrome 开发者工具显示,<p transition:fade>它会注入一个内联样式来实现淡入/淡出效果。

<script>
    import { fade } from 'svelte/transition';
    let visible = true;
</script>

{#if visible}
<p transition:fade>Fade in and out</p>
{/if}

b. 添加参数

https://svelte.dev/tutorial/adding-parameters-to-transitions

您还可以将内联参数传递给标记中的过渡函数。

<script>
    import { fly } from 'svelte/transition';
    let visible = true;
</script>

<input type=checkbox bind:checked={visible}>

{#if visible}
<p transition:fly="{{ y: 200, duration: 2000 }}">Flies in and out</p>
{/if}

过渡效果是“可逆的”。
切换可见性不会突然从开始或结束状态开始过渡,

而是会从上次停止的地方反向播放。

请参阅链接的教程页面,了解实际效果!很棒。

c. 进出

https://svelte.dev/tutorial/in-and-out

您可以使用in&out指令而不是transition.来精细地控制过渡效果。

d. 自定义 CSS 过渡

https://svelte.dev/tutorial/custom-css-transitions

只要你了解CSS的过渡和动画等技术,看起来很简单。但

我对这两方面都不太了解,所以很难。

首先要学习:MDN 上的CSS 过渡使用方法。

e. 自定义 JS 过渡

https://svelte.dev/tutorial/custom-js-transitions

使用tick回调函数来实现 CSS 过渡无法实现的 JS 过渡效果。

f. 过渡事件

https://svelte.dev/tutorial/transition-events

transition使用以下指令监控指令事件

  • on:introstart
  • on:outrostart
  • on:introend
  • on:outroend

g. 局部转变

https://svelte.dev/tutorial/local-transitions

local转换操作使转换发生在单个元素上,而不是一组元素上。

说实话,我真的没发现它有什么用。

h. 延迟过渡

https://svelte.dev/tutorial/deferred-transitions

更高级的过渡概念我以后再学。

11. 动画

a. 有生命指令

https://svelte.dev/tutorial/animate

哎呀,过会儿再来吧……

12. 行动

a. 使用指令

https://svelte.dev/tutorial/actions

使用use:指令来指定操作。

<script>
    import { pannable } from './pannable.js';
</script>
<div use:pannable></div>

pannable是一个函数,它接受一个 DOM 节点。

// Fires following custom events
// 1. panstart
// 2. panmove
// 3. panend
export function pannable(node) {}

当组件pannable分发自定义事件时,父组件可以在标记中订阅该事件。

<script>
    import { pannable } from './pannable.js';

    // These functions have access to `event` dispatched from `pannable`
    const handlePanStart = event => {}
    const handlePanMove = event => {}
    const handlePanEnd = event => {}
</script>
<div 
    use:pannable
    on:panstart={handlePanStart}
    on:panmove={handlePanMove}
    on:panend={handlePanEnd}
    style="transform:
        translate({$coords.x}px,{$coords.y}px)
        rotate({$coords.x * 0.2}deg)"
></div>

可以通过暴露来清理行动痕迹onDestroy

export function pannable(node) {
    return {
        onDesotry() {
            // clean up the mess
        }
    }
}

b. 添加参数

https://svelte.dev/tutorial/adding-parameters-to-actions

就像过渡一样,动作也可以接受参数。

<script>
    import { longpress } from './longpress.js';
</script>
<div use:longpress={duration}></div>

当持续时间发生变化时,longpress.js不会知道它duration已经发生了变化。

要订阅此duration变化,请update在操作中实现函数。

longpress.js

export function longpress(node, duration) {
    return {
        update(newDuration) {
            duration = newDuration
        }
    }
}

可以将多个参数作为对象传递给操作。

<script>
    import { longpress } from './longpress.js';
</script>
<div use:longpress={{duration, spiciness}}></div>

并在动作中接受对象。

longpress.js

export function longpress(node, { duration, spiciness }) {}

13. 课程

a. 类指令

https://svelte.dev/tutorial/classes

Svelt 提供了一个用于切换类的快捷方式。

class只是在 Svelte 中是这样className,不像在 React 中那样。

<script>let current = 'foo';</script>
<style>
    .someActiveClass {
        background-color: red;
        color: white
    }
</style>

<button 
    class:someActiveClass="{current='foo'}" 
    on:click="{() => current = 'foo'}">
>foo</button>

<button 
    class:someActiveClass="{current='bar'}" 
    on:click="{() => current = 'bar'}">
>bar</button>

<button 
    class:someActiveClass="{current='baz'}" 
    on:click="{() => current = 'baz'}">
>baz</button>

只要条件匹配,就会在后面添加自定义类class:

b. 简写类指令

https://svelte.dev/tutorial/class-shorthand

快捷方式的简写(呼,真绕口)是,如果要切换的类与变量名匹配,则可以省略指令赋值。

<div class:big={big}></div>

可以缩写为

<div class:big></div>

14. 成分组成

a. 老虎机

https://svelte.dev/tutorial/slots

这与 React 的实现方式类似children,用于指定将子组件放置在当前组件中的哪个位置。

Svelte 组件不是函数,而更像是带有脚本和样式的标记。

因此,要访问子组件,需要指定 ` <script> <slot></slot>` 或 `<style> <slot />`。

您可以指定多个<slot />,这将多次显示子项。

box.svelte

<style>
    .box {}
</style>

<div class="box">
    <slot></slot>
    <!-- or -->
    <slot />
</div>

并将子组件传递给 box 组件。

<script>
    import Box from './box.svelte';
</script>

<Box>
    <h1>Here is the child header</h1>
    <p> this is the content <p>
</Box>

个人说明:这更符合 React 应有的风格,因为 React 本来就应该是声明式的。Svelte

正确地使用了子元素的标记声明,而 React 则是命令式的children。(更不用说,`<div>`children可以是任何东西,比如一个用于实现渲染属性的函数)。

b. 槽位回退

https://svelte.dev/tutorial/slot-fallbacks

如果没有指定任何备用方案,可以使用 ` <slot />but`,但要提供备用方案(当用户没有指定子项时),则可以使用更长的 ` <slot>fallback content</slot>.`

box.svelte

<style>
    .box {}
</style>

<div class="box">
    <slot>Fallback content!!!</slot>
</div>

Box下面展示了传递无子节点的示例。

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

<Box>
    <h2>Hello!</h2>
    <p>This is a box. It can contain anything.</p>
</Box>

<Box></Box>
<Box />

c. 命名槽

https://svelte.dev/tutorial/named-slots

在 React 中,可以像这样公开单独的组件或静态子组件。

function App() {
    return (
        <ContactCard>
            <ContactCard.Name>Sung Kim</ContactCard.Name>
            <ContactCard.Address />
        </ContactCard>
    )
}
// or
function App() {
    return (
        <ContactCard>
            <ContactCardName>Sung Kim</ContactCardName>
            <ContactCardAddress />
        </ContactCard>
    )
}

ContactCardName它需要为`or`创建单独的组件ContactCardAddress,每个组件都接受自己的children函数。

接下来就更有意思了。

您可以指定要将子内容插入到哪个“槽位”中!

ContactCard.svelte

<style>
    .missing {}
</style>

<article class="contact-card">
    <h2>
        <slot name="name">
            <span class="missing">Unknown name</span>
        </slot>
    </h2>

    <div class="address">
        <slot name="address">
            <span class="missing">Unknown address</span>
        </slot>
    </div>

    <div class="email">
        <slot name="email">
            <span class="missing">Unknown email</span>
        </slot>
    </div>
</article>

如上一节所示,每个命名槽位都包含备用槽位。

调用组件指定子组件中的插槽。

App.svelte

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

<ContactCard>
    <span slot="name">Sung</span>
    <span slot="email">Sung@sung.com</span>
</ContactCard>

c. 老虎机道具

https://svelte.dev/tutorial/slot-props

要将数据从子组件传递slot到父组件,需要在声明子组件时声明暴露的状态(通过插槽)。

你不需要在父组件中声明变量,而是像使用“绑定”一样使用let

Hovering.svelte:包含插槽的组件。

<script>
    let hovering;

    const enter = () => hovering = true;
    const leave = () => hovering = false;
</script>

<div on:mouseenter={enter} on:mouseleave={leave}>
    <slot hovering={hovering}></slot>
    <!-- or use the hsort hand -->
    <!-- <slot hovering></slot> -->
</div>

hovering要在父组件中访问,请使用let前面提到的方法。

Parent.svelte

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

<Hoverable let:hovering={hovering}>
    <div class:active={hovering}>
        {#if hovering}
            <p>I am being hovered upon.</p>
        {:else}
            <p>Hover over me!</p>
        {/if}
    </div>
</Hoverable>

请注意,该hovering变量未在声明中声明script,但可以在内部使用Hovering

15. 上下文 API

a. setContext 和 getContext

https://svelte.dev/tutorial/context-api

Svelte 的 Context API 与 React 的类似;只有子组件才能通过父组件中暴露的

Context API 访问上下文数据。getContextsetContext

store更像是Zustand,其中状态在组件层次结构中的任何位置都可用。

React 和 Svelte Context API 的区别在于,React 的 API 是声明式的,使用标记语言;而 Svelte 的 API 是命令式的,setContext在组件初始化期间使用。

React

function App() {
    return (
        <Context.Provider value={value}>
            children can access context value here
        </Context.Provider>
    )
}

16. 特殊元素

a. svelte:self

https://svelte.dev/tutorial/svelte-self

递归引用当前组件。

文档中存在拼写错误,因此提交了一个 issue:https://github.com/sveltejs/svelte/issues/5044

更新“一个文件”指的是当前文件,而不是File组件。因此文档已更正。已关闭该 issue。

b. svelte:component

https://svelte.dev/tutorial/svelte-component

用于<svelte:component this={component}>动态加载组件。

要传递 props,请将其传递给<svelte:component>.

<svelte:component text="custom text" this={selected.component}/>

text然后传递给selected.component(教程中没有记录,只是偶然发现的)。

确保动态组件接受该属性。

例如)RedThing.svelte

<style>
    strong { color: red; }
</style>

<script>
    export let text = "red thing";
</script>

<strong>{text}</strong>

c. svelte:window

https://svelte.dev/tutorial/svelte-window

这是一种以声明式方式向window对象添加事件的方法。

d. svelte:window绑定

https://svelte.dev/tutorial/svelte-window-bindings

原来,你window不仅可以绑定事件,还可以绑定到某些属性。

e.苗条:身体

https://svelte.dev/tutorial/svelte-body

这样就可以在document.body.

f.苗条:头

https://svelte.dev/tutorial/svelte-head

直接在代码中注入内容<html><head>

无需react-helmet第三方库。

g. svelte:选项

https://svelte.dev/tutorial/svelte-options

Svelte 编译器的高级选项。

最值得注意的是,您可以指定不可变性来优化列表中的组件渲染。

17. 模块上下文

a. 代码共享

https://svelte.dev/tutorial/sharing-code

这看起来像是一个在组件的所有实例中都可用的“静态”变量。

可能是原型值。

b. 出口

https://svelte.dev/tutorial/module-exports

模块级脚本中的导出内容可以从另一个 Svelte 组件导入。

18. 调试

a. @debug 标签

https://svelte.dev/tutorial/debug

更好的“console.log” :p


照片由William Krause拍摄,来自Unsplash

文章来源:https://dev.to/dance2die/svelte-tutorial-note-cap