useDraggable
useDraggable wraps the createDraggable
function from AnimeJS. It makes an element draggable once the component
mounts.
nanime rebuilds the draggable when target, trigger or container
points to a new element, and keeps it disabled across the rebuild if it was.
It reverts when the component unmounts.
Usage
import { spring } from '#nanime/easings'
const container = useTemplateRef('container')
const draggable = useTemplateRef('draggable')
useDraggable(draggable, {
container: container,
releaseEase: spring({
bounce: 0.65,
duration: 400,
}),
x: {
snap: (draggable) => {
const hw = (draggable?.dragArea || [0, 0, 0, 0])[2]
const results = [0, hw * 0.35, hw * 0.75]
return results
},
},
})
<template>
<div ref="container" class="relative rounded-md border-dashed h-10">
<div class="snap-positions">
<div class="spot" style="--snap-x: 0%">0%</div>
<div class="spot" style="--snap-x: 35%">35%</div>
<div class="spot" style="--snap-x: 75%">75%</div>
</div>
<div ref="draggable" class="simple-box w-12 h-10! draggable" />
</div>
</template>
@reference "~/assets/css/main.css";
.snap-positions {
@apply absolute inset-0 pointer-events-none;
}
.snap-positions div {
@apply absolute top-0 inset-y-0 left-(--snap-x) w-12 h-10;
}
.draggable {
@apply z-10 text-black relative;
}
Signature
function useDraggable(
target: DraggableTypes['target'],
options?: DraggableOptions
): BufferedProxyReturns<Draggable>
Parameters
transform, since AnimeJS
writes it on every frame of a drag.trigger and container also accept template refs and component refs.
snap (also inside x and y), dragSpeed, scrollSpeed,
scrollThreshold, containerPadding, containerFriction, minVelocity,
maxVelocity and velocityMultiplier also accept a ref, and a change
updates the draggable in place.Returns
Returns a buffered proxy around the AnimeJS Draggable.
Its methods and properties are in the
AnimeJS draggable documentation.
The draggable is created when the component mounts. Methods such as
disable() can be called straight from setup(), and run at that point.
Read properties such as x and y after
mount.
Caveats
Read properties after mount
// wrong: reading position before mount returns undefined
const draggable = useDraggable('.card')
console.log(draggable.x) // undefined
// right: read coordinates after mount or inside interaction callbacks
onMounted(() => {
console.log(draggable.x)
})
The underlying Draggable instance is constructed after the component mounts
and resolves its target element. Chainable methods buffer safely before mount,
but property reads and non-chainable helper methods return undefined until the
instance exists. Access coordinates inside lifecycle hooks or callbacks such as
onDrag.
Type reference
type DraggableTargets = DOMTargetSelector | MaybeElementRef<HTMLElement | SVGElement | VueInstance | null> | null | undefined
type DraggableTargetContainer = DraggableParams['container'] | MaybeElementRef<HTMLElement | VueInstance | null> | null | undefined
type DraggableTargetTrigger = DraggableParams['trigger'] | DraggableTargets
type DraggableTypes = {
target: DraggableTargets
trigger: DraggableTargetTrigger
container: DraggableTargetContainer
}
type DraggableOptions = MakeRefable<Omit<DraggableParams, 'trigger' | 'container' | 'x' | 'y'> & {
trigger?: DraggableTypes['trigger']
container?: DraggableTypes['container']
x?: boolean | Prettify<MakeRefable<DraggableAxisParam, 'snap', Draggable>>
y?: boolean | Prettify<MakeRefable<DraggableAxisParam, 'snap', Draggable>>
}, RefableProps, Draggable>
type BufferedProxyReturns<T> = Exclude<UnwrapNestedRefs<T>, null | undefined>
See also
useAnimatable: reactive tweening for fast pointer updates- Drive: drag files onto a trash target in a file manager
- AnimeJS draggable documentation: upstream axis locking and snap configuration