Clickable slide: don't allow clit during "sliding"
kiuKisas opened this issue · 1 comments
Hey, I have a slider made of a
link. When I grab the slider to move it, it click on my slide when I release. It shouldn't
Hello @kiuKisas. I got this exact same issue while using on:click on the carousel slides.
This svelte-carousel is a wrapper for a vanilla js library called Siema. Sadly, Siema is no longer under development/maintenance by the author. I came up with a simple solution which I hope works for you too.
Quick solution:
1. Create a preciseClick.js file with the following code:
export default (node, threshold = 8) => {
// Set initial values
let moved = false,
initialPosition = { x: null, y: null };
const handleMousedown = (e) => {
console.log("mousedown");
e.preventDefault();
initialPosition.x = e.x;
initialPosition.y = e.y;
moved = false;
};
const handleMouseup = (e) => {
console.log("mouseup");
if (
!(initialPosition.x + threshold >= e.x) ||
!(initialPosition.x - threshold <= e.x)
) {
moved = true;
}
if (
!(initialPosition.y + threshold >= e.y) ||
!(initialPosition.y - threshold <= e.y)
) {
moved = true;
}
};
const handleClick = (e) => {
if (moved) {
e.preventDefault();
} else {
const preciseClickEvent = new CustomEvent("preciseClick", {
detail: { moved, initialPosition },
});
node.dispatchEvent(preciseClickEvent);
}
};
node.addEventListener("click", handleClick);
node.addEventListener("mousedown", handleMousedown);
node.addEventListener("mouseup", handleMouseup);
return {
destroy() {
node.removeEventListener("click", handleClick);
node.removeEventListener("mousedown", handleMousedown);
node.removeEventListener("mouseup", handleMouseup);
},
};
};
2. Then use on your carousel slides like this:
<script>
import Carousel from '@beyonk/svelte-carousel'
import preciseClick from './preciseClick.js'
</script>
<Carousel dots={false}>
<!-- Default threshold is 8 -->
<a href="https://google.com" class="slide-content" use:preciseClick>Slide 1</a>
<!-- You can set a different value for threshold like this -->
<a href="https://google.com" class="slide-content" use:preciseClick={24}>Slide 2</a>
<!-- It should work on a <a> contained in slide-content too -->
<div class="slide-content">
<a href="https://google.com" use:preciseClick>Slide 4</a>
</div>
<!-- if you want to do something when the click is between the threshold listen to this custom event instead of 'click' -->
<div class="slide-content" use:preciseClick on:preciseClick={()=>{ alert('clicked') }}>
Some content
</div>
</Carousel>
How it works
I created a Svelte action that listens to the mousedown and mouseup events over a certain element, i.e. a carousel slide. On mousedown it will set a boolean 'moved' flag to false and will store the x and y position of the event.
On mouseup it will check if the cursor moved by a variable amount of pixels. If it did, the 'moved' flag is set to true, else it will remain false.
This flag is then evaluated to decide whether an event should be emitted:
- If the flag was set to true when the click event happens then the default click behavior will be prevented
- If the flag was set to false, the click behavior will be as expected. Also a custom 'preciseClick' event will fire in case you need to do something when the click is between the threshold.
REPL demo:
https://svelte.dev/repl/ac2a89e08f1d4600a88da743dcede207?version=3.38.3
I might submit a pull request with a built-in implementation of this solution later although I'm not sure if this is part of the intended scope or responsibility of this svelte-carousel component. For the time being you could use this action.