I need a long press event to bind to buttons in svelte 3. I want to do this in the least "boilerplaty" way possible.
I've tried with a long press function but this seems a little convoluted and hacky, also seems a little slow.
function longPress(node, callback) {
console.log(node)
function onmousedown(event) {
const timeout = setTimeout(() => callback(node.innerHTML), 1000);
function cancel() {
clearTimeout(timeout);
node.removeEventListener("mouseup", cancel, false);
}
node.addEventListener("mouseup", cancel, false);
}
node.addEventListener("mousedown", onmousedown, false);
return {
destroy() {
node.removeEventListener("mousedown", onmousedown, false);
}
};
}
</script>
<div>
<Video />
{#each Object.entries(bindings) as [id, value]}
<button on:click = {()=>longPress(this,addImage)}> {id} </button>
{/each}
</div>
This works but I'm sure there is a better way.
For this sort of thing I would use an action, which is a function that runs when an element is created (and can return functions that are run when parameters are changed, or the element is destroyed): https://svelte.dev/tutorial/actions
In this case you could create a reusable longpress
action, much like your function above, which dispatches a custom longpress
event on the target element that you can listen for like a native DOM event:
<script>
import { longpress } from './actions.js';
let pressed;
</script>
<button use:longpress on:longpress="{e => pressed = true}">
longpress me
</button>
export function longpress(node, threshold = 500) {
// note — a complete answer would also consider touch events
const handle_mousedown = () => {
let start = Date.now();
const timeout = setTimeout(() => {
node.dispatchEvent(new CustomEvent('longpress'));
}, threshold);
const cancel = () => {
clearTimeout(timeout);
node.removeEventListener('mousemove', cancel);
node.removeEventListener('mouseup', cancel);
};
node.addEventListener('mousemove', cancel);
node.addEventListener('mouseup', cancel);
}
node.addEventListener('mousedown', handle_mousedown);
return {
destroy() {
node.removeEventListener('mousedown', handle_mousedown);
}
};
}
The advantage of this approach is that you've separated the definition of 'longpress' from the thing that handles it, so the addImage
/node.innerHTML
logic can be cleanly separated, and you can re-use the action elsewhere in your app.
Full demo, including passing a parameter to the action: https://svelte.dev/repl/f34b6159667247e6b6abb5142b276483?version=3.6.3