事件处理
本教程共 50 篇 · 第 18 篇 · 更新于 2026-08-05 · 约 6 分钟阅读
18. 事件处理
本节目标:学会在 Svelte 5 中用
onclick属性式写法监听 DOM 事件,掌握事件对象、内联处理器和事件修饰符的用法,了解与 Svelte 4 的差异。
属性式事件:onclick 而非 on:click
Svelte 5 做了一个很大的改变:事件处理不再是指令,而是普通的属性。
什么意思呢?在 Svelte 4 里,你监听点击事件要写 on:click,中间有个冒号。Svelte 5 把它简化成了 onclick,跟原生 HTML 的写法一模一样。
<script>
let count = $state(0);
</script>
<!-- Svelte 5 写法:事件就是一个属性 -->
<button onclick={() => count += 1}>
点击次数:{count}
</button>
这个改动的好处是,事件跟 class、href 这些属性地位一样了。你可以用简写形式,也可以用展开语法。
<script>
let count = $state(0);
function onclick() {
count += 1;
}
</script>
<!-- 简写形式:变量名和属性名相同 -->
<button {onclick}>
点击次数:{count}
</button>
Note简写要求变量名和属性名完全一致。如果你的函数叫
handleClick,就不能简写,得写完整形式onclick={handleClick}。事件属性是大小写敏感的。
onclick监听的是click事件,而onClick监听的是Click事件,两者完全不同。这让你可以监听名称中包含大写字母的自定义事件。
事件对象
事件处理函数会自动收到一个事件对象参数,跟原生 DOM 事件一模一样。
<script>
function handleClick(event) {
// event 就是原生的 MouseEvent
console.log('点击坐标:', event.clientX, event.clientY);
}
</script>
<button onclick={handleClick}>点我</button>
如果你用的是内联箭头函数,事件对象需要你手动接收。
<script>
let lastX = $state(0);
</script>
<!-- 内联写法,event 需要手动写出来 -->
<button onclick={(event) => lastX = event.clientX}>
记录 X 坐标:{lastX}
</button>
内联处理器
内联处理器就是在属性里直接写箭头函数。它的好处是可以直接访问外层变量,不需要额外定义函数。
<script>
let name = $state('');
function greet(greeting, event) {
console.log(`${greeting},${name}!`);
console.log('事件来源:', event.target);
}
</script>
<input bind:value={name} placeholder="输入名字" />
<!-- 内联处理器可以传额外参数 -->
<button onclick={(e) => greet('你好', e)}>
打招呼
</button>
TipSvelte 的内联处理器不会有性能损失。编译器会自动优化,不需要担心性能问题。
事件修饰符
在 Svelte 4 里,事件修饰符用 | 管道符来加,比如 on:click|preventDefault。Svelte 5 推荐你在函数里手动处理。
最常见的需求是阻止默认行为和阻止冒泡。
<script>
function handleSubmit(event) {
// 手动阻止默认行为
event.preventDefault();
console.log('表单已提交');
}
function handleClick(event) {
// 手动阻止冒泡
event.stopPropagation();
console.log('只会触发一次');
}
</script>
<form onsubmit={handleSubmit}>
<button type="submit">提交</button>
</form>
<div onclick={() => console.log('外层 div')}>
<button onclick={handleClick}>内层按钮</button>
</div>
不过如果你怀念 Svelte 4 的修饰符语法,在 on: 指令(旧语法)中仍然支持这些修饰符:
| 修饰符 | 作用 |
|---|---|
preventDefault | 调用 event.preventDefault() |
stopPropagation | 阻止事件冒泡 |
stopImmediatePropagation | 阻止同事件的其他监听器 |
passive | 提升触摸/滚轮事件性能 |
nonpassive | 显式设置 passive: false |
capture | 在捕获阶段触发 |
once | 只触发一次 |
self | 仅当 target 是元素本身时触发 |
trusted | 仅当 event.isTrusted 为 true 时触发 |
<!-- Svelte 4 旧写法(仍然支持,但不推荐) -->
<form on:submit|preventDefault={handleSubmit}>
<button type="submit">提交</button>
</form>
Note在 Svelte 5 的 Runes 模式下,推荐使用
onclick属性式写法,在函数体内手动处理preventDefault等逻辑。on:指令仅作为迁移过渡使用。
多个事件监听器
同一个元素可以绑定多个相同类型的事件处理器,它们会按顺序执行。
<script>
let count = $state(0);
function increment() {
count += 1;
}
function log(event) {
console.log('事件对象:', event);
}
</script>
<!-- 两个 click 处理器都会执行 -->
<button onclick={increment} onclick={log}>
点击次数:{count}
</button>
事件委托
为了提升性能,Svelte 对部分事件使用了事件委托技术。具体来说,Svelte 会在应用根节点上挂一个监听器,统一处理这些事件。
被委托的事件包括:
click、dblclick、contextmenuinput、change、beforeinputkeydown、keyupmousedown、mousemove、mouseover、mouseout、mouseuppointerdown、pointermove、pointerover、pointerout、pointeruptouchstart、touchmove、touchendfocusin、focusout
Tip如果你需要手动派发一个被委托的事件,记得设置
{ bubbles: true },否则事件无法到达应用根节点。
时序问题
事件属性的触发时机有个细节你需要知道:事件处理器总是在绑定更新之后触发。
比如 oninput 总是在 bind:value 更新之后才执行。这意味着你在 oninput 里读到的已经是最新值。
<script>
let text = $state('');
function handleInput(event) {
// 此时 text 已经是输入框的最新值
console.log('绑定值:', text);
console.log('事件值:', event.target.value);
}
</script>
<!-- oninput 会在 bind:value 更新后触发 -->
<input bind:value={text} oninput={handleInput} />
与 Svelte 4 对照
| 对比项 | Svelte 4 | Svelte 5 |
|---|---|---|
| 事件绑定 | on:click={fn} | onclick={fn} |
| 修饰符 | on:click|preventDefault | 函数内手动 event.preventDefault() |
| 简写 | 不支持 | {onclick}(变量名需和属性名一致) |
| 展开 | 不支持 | {...eventProps} |
| 组件事件 | createEventDispatcher | 回调 Props(下一章讲) |
Note如果你从 Svelte 4 迁移过来,
on:click语法仍然可用,但官方推荐使用onclick属性式写法。
本节回顾
- Svelte 5 用
onclick属性式写法替代了 Svelte 4 的on:click指令 - 事件处理函数自动接收原生事件对象
- 内联箭头函数写法没有性能损失,可以自由使用
- 事件修饰符改为在函数体内手动处理(
preventDefault、stopPropagation等) - Svelte 对部分事件使用事件委托来优化性能
- 事件处理器总是在绑定更新之后触发