Svelte 官方入门教程(5) - 事件

svelte cover

上一讲中,我们使用过on:click={toggle},今天咱们就详细讲解下事件。

一、DOM事件

来看个一例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script>
let m = { x: 0, y: 0 };

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

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

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

正如我们上一讲中已经简要看到的,您可以使用 on: 指令,监听元素上的任何事件

二、内联事件

您还可以内联声明事件处理程序:

1
2
3
4
5
6
7
8
9
10
11
<script>
let m = { x: 0, y: 0 };
</script>

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

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

还是上面的例子,我们可以把事件采用内联的写法。

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

上面的on:mousemove="{e => m = { x: e.clientX, y: e.clientY }}"可以看到内联的事件写在了""内,其实属性值上的双引号是可选的,只是某些环境下有助于语法突出显示

在某些框架中,您可能会看到出于性能原因避免使用内联事件处理程序的建议,尤其是内部循环。 该建议不适用于 Svelte — 无论您选择哪种形式,编译器都会始终做正确的事情。

三、事件修饰符

DOM 事件处理程序具有额外的 修饰符(modifiers) 。 例如,带 once 修饰符的事件处理程序只运用一次:

1
2
3
4
5
6
7
8
9
<script>
function handleClick() {
alert('no more alerts')
}
</script>

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

通过上面的例子你不难发现事件修饰符的使用方式,事件|修饰符

下面列出所有的修饰符供大家参考(所有的指的是当前版本下)

  • preventDefault :调用event.preventDefault() ,在运行处理程序之前调用。比如,对客户端表单处理有用。
  • stopPropagation :调用 event.stopPropagation(), 防止事件影响到下一个元素。
  • passive : 优化了对 touch/wheel 事件的滚动表现(Svelte 会在合适的地方自动添加滚动条)。
  • capture — 在 capture 阶段而不是bubbling 阶段触发事件处理程序
  • once :运行一次事件处理程序后将其删除。
  • self — 仅当 event.target 是其本身时才执行。
  • trusted — 仅当事件是由用户行为生成的时候,这个属性的值为 true,属性是一个只读属性。

你可以将修饰符组合在一起使用,例如:on:click|once|capture={...}

四、组件事件

组件也可以调度事件,为此,组件内必须创建一个相同事件并在外部进行分配。 更改 Inner.svelte

1
2
3
4
5
6
7
8
9
10
11
<script>
import { createEventDispatcher } from 'svelte';

const dispatch = createEventDispatcher();

function sayHello() {
dispatch('message', {
text: 'Hello!'
});
}
</script>

createEventDispatcher 必须在首次实例化组件时调用它,—组件本身不支持如 setTimeout 之类的事件回调。 定义一个dispatch进行连接,进而把组件实例化。

然后我们把Inner组件引入到App组件中

1
2
3
4
5
6
7
8
9
<script>
import Inner from './Inner.svelte';

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

<Inner on:message={handleMessage}/>

请注意,由于 on:message 指令,App 组件正在侦听 Inner 组件发送的消息。 该指令是一个以 on: 为前缀的属性,后跟我们正在调度的事件名称(在本例中为message)。

如果没有这个属性,消息仍然会被发送,但应用程序不会对其做出反应。 您可以尝试删除 on:message 属性并再次按下按钮。

您也可以尝试将事件名称更改为其他名称。 例如,将 Inner.svelte 中的 dispatch('message') 更改为 dispatch('myevent') 并将 App.svelte 组件中的属性名称从 on:message 更改为 on:myevent

REPL

五、事件转发

DOM 事件不同, 组件事件不会 冒泡(bubble) ,如果你想要在某个深层嵌套的组件上监听事件,则中间组件必须 转发(forward) 该事件。

在这种情况下,我们具有与上一节相同的 App.svelteInner.svelte,不过现在还需创建一个 Outer.svelte,并且在 Outer.svelte 组件中添加 <Inner/>

解决这个问题的方法之一是添加 createEventDispatcherOuter.svelte中,监听其 message 事件,并为它创建一个转发程序:
Outer.svelte

1
2
3
4
5
6
7
8
9
10
11
12
<script>
import Inner from './Inner.svelte';
import { createEventDispatcher } from 'svelte';

const dispatch = createEventDispatcher();

function forward(event) {
dispatch('message', event.detail);
}
</script>

<Inner on:message={forward}/>

但这样书写似乎有些臃肿,因此 Svelte 设立了一个简写属性 on:message。 message 没有赋予特定的值得情况下意味着转发所有massage事件:

但是这样要写很多重复的代码,所以Svelte 为我们提供了一个等效的简写方式 —— 一个没有值的 on:message 事件指令意味着“转发所有消息事件”

1
2
3
4
5
<script>
import Inner from './Inner.svelte';
</script>

<Inner on:message/>

REPL

六、DOM事件转发

事件转发也是可以应用到标准的DOM事件上的。

看例子:
FancyButton

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<style>
button {
height: 4rem;
width: 8rem;
background-color: #aaa;
border-color: #f1c40f;
color: #f1c40f;
font-size: 1.25rem;
background-image: linear-gradient(45deg, #f1c40f 50%, transparent 50%);
background-position: 100%;
background-size: 400%;
transition: background 300ms ease-in-out;
}
button:hover {
background-position: 0;
color: #aaa;
}
</style>

<button>
Click me
</button>

App

1
2
3
4
5
6
7
8
9
<script>
import FancyButton from './FancyButton.svelte';

function handleClick() {
alert('clicked');
}
</script>

<FancyButton on:click={handleClick}/>

我们希望<FancyButton>组件内部接收外部的handleClick(),为此,我们只需要为FancyButton.svelte内的<button>标签添加click 事件即可:

1
2
3
<button on:click>
Click me
</button>

总结

  • 使用 on: 指令,例如 on:click,也可以直接内联一个函数的形式 on:click={ () => … },并且内联的不会有性能问题,还可以将函数提到外部的形式 on:click={ handler }。两者的结果没有什么区别。
  • 支持绑定组件的自定义事件,组件需要使用 createEventDispatcher() 方法将事件转发。

Svelte 官方入门教程(5) - 事件
http://yoursite.com/2022/07/12/svelte-tutorial-5/
作者
昂藏君子
发布于
2022年7月12日
许可协议