You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte/site/content/guide/07-events.md

4.4 KiB

title
Events

In most applications, you'll need to respond to the user's actions. In Svelte, this is done with the on:[event] directive.

Element events

When used on an element, on:click={handler} is equivalent to calling element.addEventListener('click', handler). When the element is removed, Svelte calls removeEventListener automatically.

<!-- { title: 'Inline event handlers' } -->
<p>Count: {count}</p>
<button on:click="{() => count += 1}">+1</button>
/* { hidden: true } */
{
	count: 0
}

For more complicated behaviours, you'll probably want to declare an event handler in your <script> block:

<!-- { title: 'Event handlers' } -->
<script>
	let count = 0;

	function incrementOrDecrement(event) {
		const d = event.shiftKey
			? -1
			: +1;

		count += d;
	}
</script>

<p>Count: {count}</p>
<button on:click={incrementOrDecrement}>update</button>
/* { hidden: true } */
{
	count: 0
}

Event handler modifiers

While you can invoke methods like event.stopPropagation directly...

<!-- { repl: false } -->
<div on:click="{e => e.stopPropagation()}">...</div>

...it gets annoying if you want to combine that with some other behaviour:

<!-- { repl: false } -->
<script>
	let foo = false;

	function toggleFoo(event) {
		event.stopPropagation();
		event.preventDefault();
		foo = !foo;
	}
</script>

<div on:click={toggleFoo}>...</div>

For that reason, Svelte lets you use event modifiers:

passive and once are not implemented in legacy mode

The example above can be achieved with modifiers — no need for a separate event handler:

<!-- { repl: false } -->
<div on:click|stopPropagation|preventDefault="{() => foo = !foo}">...</div>

Component events

Events are an excellent way for nested components to communicate with their parents. Let's revisit our earlier example, but turn it into a <CategoryChooser> component:

<!-- { filename: 'CategoryChooser.html', repl: false } -->
<p>Select a category:</p>

{#each categories as category}
	<button on:click="fire('select', { category })">select {category}</button>
{/each}

<script>
	export default {
		data() {
			return {
				categories: [
					'animal',
					'vegetable',
					'mineral'
				]
			}
		}
	};
</script>

When the user clicks a button, the component will fire a select event, where the event object has a category property. Any component that nests <CategoryChooser> can listen for events like so:

<!--{ title: 'Component events' }-->
<CategoryChooser on:select="playTwentyQuestions(event.category)"/>

<script>
	import CategoryChooser from './CategoryChooser.html';

	export default {
		components: {
			CategoryChooser
		},

		methods: {
			playTwentyQuestions(category) {
				alert(`ok! you chose ${category}`);
			}
		}
	};
</script>
<!--{ filename: 'CategoryChooser.html', hidden: true }-->
<p>Select a category:</p>

{#each categories as category}
	<button on:click="fire('select', { category })">select {category}</button>
{/each}

<script>
	export default {
		data() {
			return {
				categories: [
					'animal',
					'vegetable',
					'mineral'
				]
			}
		}
	};
</script>

Just as this in an element's event handler refers to the element itself, in a component event handler this refers to the component firing the event.

There is also a shorthand for listening for and re-firing an event unchanged.

<!-- { repl: false } -->
<!-- these are equivalent -->
<Widget on:foo="fire('foo', event)"/>
<Widget on:foo/>

Since component events do not propagate as DOM events do, this can be used to pass events through intermediate components. This shorthand technique also applies to element events (on:click is equivalent to on:click="fire('click', event)").