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/tutorial/12-actions/01-actions/text.md

2.4 KiB

title
The use directive

Actions are essentially element-level lifecycle functions. They're useful for things like:

  • interfacing with third-party libraries
  • lazy-loaded images
  • tooltips
  • adding custom event handlers

In this app, we want to make the orange box 'pannable'. It has event handlers for the panstart, panmove and panend events, but these aren't native DOM events. We have to dispatch them ourselves. First, import the pannable function...

import { pannable } from './pannable.js';

...then use it with the element:

<div class="box"
	use:pannable
	on:panstart={handlePanStart}
	on:panmove={handlePanMove}
	on:panend={handlePanEnd}
	style="transform: translate({$coords.x}px,{$coords.y}px)"
></div>

Open the pannable.js file. Like transition functions, an action function receives a node and some optional parameters, and returns an action object. That object can have a destroy function, which is called when the element is unmounted.

We want to fire panstart event when the user mouses down on the element, panmove events (with dx and dy properties showing how far the mouse moved) when they drag it, and panend events when they mouse up. One possible implementation looks like this:

export function pannable(node) {
	let x;
	let y;

	function handleMousedown(event) {
		x = event.clientX;
		y = event.clientY;

		node.dispatchEvent(new CustomEvent('panstart', {
			detail: { x, y }
		}));

		window.addEventListener('mousemove', handleMousemove);
		window.addEventListener('mouseup', handleMouseup);
	}

	function handleMousemove(event) {
		const dx = event.clientX - x;
		const dy = event.clientY - y;
		x = event.clientX;
		y = event.clientY;

		node.dispatchEvent(new CustomEvent('panmove', {
			detail: { x, y, dx, dy }
		}));
	}

	function handleMouseup(event) {
		x = event.clientX;
		y = event.clientY;

		node.dispatchEvent(new CustomEvent('panend', {
			detail: { x, y }
		}));

		window.removeEventListener('mousemove', handleMousemove);
		window.removeEventListener('mouseup', handleMouseup);
	}

	node.addEventListener('mousedown', handleMousedown);

	return {
		destroy() {
			node.removeEventListener('mousedown', handleMousedown);
		}
	};
}

Update the pannable function and try moving the box around.

This implementation is for demonstration purposes — a more complete one would also consider touch events.