Overview
The useZoomImageMove composable provides move-based image zoom functionality where the zoomed image follows the cursor or touch position within the container. This creates an intuitive magnification effect that tracks mouse or touch movement.
Signature
function useZoomImageMove(): {
createZoomImage: (
container: HTMLElement,
options?: ZoomImageMoveOptions
) => void
zoomImageState: ZoomImageMoveState
}
Return Value
Initializes the move zoom functionality on the specified container element.
zoomImageState
ZoomImageMoveState
required
Reactive state object containing current zoom propertieszoomedImgStatus
'idle' | 'loading' | 'loaded' | 'error'
Loading status of the zoomed image
Examples
Basic Usage
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useZoomImageMove } from '@zoom-image/vue'
const imageContainerRef = ref<HTMLDivElement>()
const { createZoomImage } = useZoomImageMove()
onMounted(() => {
if (imageContainerRef.value) {
createZoomImage(imageContainerRef.value, {
zoomImageSource: '/high-res-image.jpg'
})
}
})
</script>
<template>
<div>
<p>Move mouse inside the image to see zoom effect</p>
<div
ref="imageContainerRef"
class="relative h-[300px] w-[200px] cursor-crosshair overflow-hidden"
>
<img src="/sample.jpg" alt="Zoomable image" class="h-full w-full" />
</div>
</div>
</template>
With Custom Zoom Factor
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useZoomImageMove } from '@zoom-image/vue'
const imageContainerRef = ref<HTMLDivElement>()
const { createZoomImage } = useZoomImageMove()
onMounted(() => {
if (imageContainerRef.value) {
createZoomImage(imageContainerRef.value, {
zoomImageSource: '/high-res-image.jpg',
zoomFactor: 6
})
}
})
</script>
<template>
<div
ref="imageContainerRef"
class="relative h-[300px] w-[200px] cursor-crosshair overflow-hidden"
>
<img src="/sample.jpg" alt="Zoomable image" class="h-full w-full" />
</div>
</template>
With State Monitoring
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useZoomImageMove } from '@zoom-image/vue'
const imageContainerRef = ref<HTMLDivElement>()
const { createZoomImage, zoomImageState } = useZoomImageMove()
onMounted(() => {
if (imageContainerRef.value) {
createZoomImage(imageContainerRef.value, {
zoomImageSource: '/high-res-image.jpg'
})
}
})
</script>
<template>
<div>
<p>Status: {{ zoomImageState.zoomedImgStatus }}</p>
<div
ref="imageContainerRef"
class="relative h-[300px] w-[200px] cursor-crosshair overflow-hidden"
>
<img src="/sample.jpg" alt="Zoomable image" class="h-full w-full" />
<div
v-if="zoomImageState.zoomedImgStatus === 'loading'"
class="absolute inset-0 flex items-center justify-center bg-black bg-opacity-50 text-white"
>
Loading high-res image...
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useZoomImageMove } from '@zoom-image/vue'
const imageContainerRef = ref<HTMLDivElement>()
const { createZoomImage } = useZoomImageMove()
onMounted(() => {
if (imageContainerRef.value) {
createZoomImage(imageContainerRef.value, {
zoomImageSource: '/high-res-image.jpg',
zoomFactor: 3,
disabledContextMenu: true,
zoomImageProps: {
alt: 'Zoomed product image',
className: 'touch-none'
}
})
}
})
</script>
<template>
<div
ref="imageContainerRef"
class="relative h-[300px] w-[200px] cursor-crosshair overflow-hidden touch-none"
>
<img src="/sample.jpg" alt="Product" class="h-full w-full" />
</div>
</template>
Dynamic Image Source
<script setup lang="ts">
import { ref, onMounted, watch } from 'vue'
import { useZoomImageMove } from '@zoom-image/vue'
const imageContainerRef = ref<HTMLDivElement>()
const currentImage = ref('/image-1.jpg')
const { createZoomImage } = useZoomImageMove()
const images = [
{ thumb: '/image-1.jpg', full: '/image-1-full.jpg' },
{ thumb: '/image-2.jpg', full: '/image-2-full.jpg' },
{ thumb: '/image-3.jpg', full: '/image-3-full.jpg' }
]
const selectImage = (image: typeof images[0]) => {
currentImage.value = image.thumb
if (imageContainerRef.value) {
createZoomImage(imageContainerRef.value, {
zoomImageSource: image.full,
zoomFactor: 4
})
}
}
onMounted(() => {
if (imageContainerRef.value) {
createZoomImage(imageContainerRef.value, {
zoomImageSource: images[0].full
})
}
})
</script>
<template>
<div>
<div class="flex gap-2 mb-4">
<button
v-for="(image, idx) in images"
:key="idx"
@click="selectImage(image)"
class="px-3 py-1 bg-gray-100 rounded"
>
Image {{ idx + 1 }}
</button>
</div>
<div
ref="imageContainerRef"
class="relative h-[300px] w-[200px] cursor-crosshair overflow-hidden"
>
<img :src="currentImage" alt="Product" class="h-full w-full" />
</div>
</div>
</template>
Options API Example
<script lang="ts">
import { defineComponent } from 'vue'
import { useZoomImageMove } from '@zoom-image/vue'
export default defineComponent({
setup() {
return useZoomImageMove()
},
mounted() {
const container = this.$refs.imageContainer as HTMLDivElement
if (container) {
this.createZoomImage(container, {
zoomImageSource: '/high-res-image.jpg',
zoomFactor: 5
})
}
}
})
</script>
<template>
<div
ref="imageContainer"
class="relative h-[300px] w-[200px] cursor-crosshair overflow-hidden"
>
<img src="/sample.jpg" alt="Product" class="h-full w-full" />
</div>
</template>
Cleanup
The composable automatically cleans up event listeners, DOM elements, and resources when the component is unmounted using Vue’s onUnmounted hook. If you need to reinitialize the zoom on the same container, simply call createZoomImage again - it will automatically clean up the previous instance.
<script setup lang="ts">
import { ref } from 'vue'
import { useZoomImageMove } from '@zoom-image/vue'
const imageContainerRef = ref<HTMLDivElement>()
const { createZoomImage } = useZoomImageMove()
const changeZoomFactor = (factor: number) => {
if (imageContainerRef.value) {
// Previous instance is automatically cleaned up
createZoomImage(imageContainerRef.value, {
zoomFactor: factor
})
}
}
</script>
See Also