Svelte 官方入门教程(15) - 模块上下文

svelte cover

上一讲是svelte的特殊元素,这些特殊元素区别于咱们的html元素,有特殊的能力,今天咱们来看模块上下文,前面咱们也讲过上下文。我们来看看异同。

共享代码

在到目前为止我们看到的所有示例中,<script> 块包含在每个组件实例初始化时运行的代码。 对于绝大多数组件,这就是您所需要的。

有时,你需要在单个组件中的实例之外运行一些代码。例如,你可以同时播放这五个音频播放器。假设现在的交互是这么设计的:其中一个播放完毕,则同时也停止其他播放器。

来看例子:

App.svelte

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<script>
import AudioPlayer from './AudioPlayer.svelte';
</script>

<!-- https://musopen.org/music/9862-the-blue-danube-op-314/ -->
<AudioPlayer
src="https://sveltejs.github.io/assets/music/strauss.mp3"
title="The Blue Danube Waltz"
composer="Johann Strauss"
performer="European Archive"
/>

<!-- https://musopen.org/music/43775-the-planets-op-32/ -->
<AudioPlayer
src="https://sveltejs.github.io/assets/music/holst.mp3"
title="Mars, the Bringer of War"
composer="Gustav Holst"
performer="USAF Heritage of America Band"
/>

<!-- https://musopen.org/music/8010-3-gymnopedies/ -->
<AudioPlayer
src="https://sveltejs.github.io/assets/music/satie.mp3"
title="Gymnopédie no. 1"
composer="Erik Satie"
performer="Prodigal Procrastinator"
/>

<!-- https://musopen.org/music/2567-symphony-no-5-in-c-minor-op-67/ -->
<AudioPlayer
src="https://sveltejs.github.io/assets/music/beethoven.mp3"
title="Symphony no. 5 in Cm, Op. 67 - I. Allegro con brio"
composer="Ludwig van Beethoven"
performer="European Archive"
/>

<!-- https://musopen.org/music/43683-requiem-in-d-minor-k-626/ -->
<AudioPlayer
src="https://sveltejs.github.io/assets/music/mozart.mp3"
title="Requiem in D minor, K. 626 - III. Sequence - Lacrymosa"
composer="Wolfgang Amadeus Mozart"
performer="Markus Staab"
/>

AudioPlayer.svelte

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<script>
export let src;
export let title;
export let composer;
export let performer;

let audio;
let paused = true;

function stopOthers() {
// TODO: implement stopOthers
}
</script>

<article class:playing={!paused}>
<h2>{title}</h2>
<p><strong>{composer}</strong> / performed by {performer}</p>

<audio
bind:this={audio}
bind:paused
on:play={stopOthers}
controls
{src}
></audio>
</article>

<style>
article {
margin: 0 0 1em 0; max-width: 800px;
}
h2, p {
margin: 0 0 0.3em 0;
}
audio {
width: 100%; margin: 0.5em 0 1em 0;
}
.playing {
color: #ff3e00;
}
</style>

如果要实现上述的情况,我们可以通过声明一个 <script context="module"> 块来做到这一点。 包含在其中的代码将在模块第一次评估时运行一次,而不是在实例化组件时运行。 将它放在 AudioPlayer.svelte 的顶部:

1
2
3
<script context="module">
let current;
</script>

现在组件可以在没有任何状态管理的情况下相互“对话”:

1
2
3
4
function stopOthers() {
if (current && current !== audio) current.pause();
current = audio;
}

可以实际操作下来体会:

二、导出

context="module"代码块中导出的任意内容,都将成为模块本身的导出。如果我们从AudioPlayer.svelte中导出stopAll函数…

AudioPlayer.svelte

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<script context="module">
const elements = new Set();

export function stopAll() {
elements.forEach(element => {
element.pause();
});
}
</script>

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

export let src;
export let title;
export let composer;
export let performer;

let audio;
let paused = true;

onMount(() => {
elements.add(audio);
return () => elements.delete(audio);
});

function stopOthers() {
elements.forEach(element => {
if (element !== audio) element.pause();
});
}
</script>

<article class:playing={!paused}>
<h2>{title}</h2>
<p><strong>{composer}</strong> / performed by {performer}</p>

<audio
bind:this={audio}
bind:paused
on:play={stopOthers}
controls
{src}
></audio>
</article>

<style>
article {
margin: 0 0 1em 0; max-width: 800px;
}
h2, p {
margin: 0 0 0.3em 0;
}
audio {
width: 100%; margin: 0.5em 0 1em 0;
}
.playing {
color: #ff3e00;
}
</style>

然后我们可以在 App.svelte 中导入AudioPlayer.svelte

1
2
3
<script>
import AudioPlayer, { stopAll } from './AudioPlayer.svelte';
</script>

并在事件处理程序中使用它:

1
2
3
<button on:click={stopAll}>
stop all audio
</button>

您不能有默认导出,因为该组件是默认导出。

可以实际操作下来体会:

总结

  • 一个<script> 标签具有一个context="module"属性,在模块首次 evaluates 时运行一次,而不是针对每个组件实例运行一次。

  • 带有 module 声明的 <script> 内代码不具有反应性。虽然变量自身会更新,但重新分配它们不会触发重新渲染,对于多个组件之间共享的值,请考虑使用 stores

  • 你不能使用 export default来绑定,因为组件本身就是默认导出(export default)


Svelte 官方入门教程(15) - 模块上下文
http://yoursite.com/2022/07/28/svelte-tutorial-15/
作者
昂藏君子
发布于
2022年7月28日
许可协议