mirror of
https://github.com/DavidHDev/vue-bits.git
synced 2026-03-07 22:49:31 -07:00
Component Boom
This commit is contained in:
84
src/content/Animations/Magnet/Magnet.vue
Normal file
84
src/content/Animations/Magnet/Magnet.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<div ref="magnetRef" :class="wrapperClassName" :style="{ position: 'relative', display: 'inline-block' }"
|
||||
v-bind="$attrs">
|
||||
<div :class="innerClassName" :style="{
|
||||
transform: `translate3d(${position.x}px, ${position.y}px, 0)`,
|
||||
transition: transitionStyle,
|
||||
willChange: 'transform',
|
||||
}">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
|
||||
|
||||
interface Props {
|
||||
padding?: number
|
||||
disabled?: boolean
|
||||
magnetStrength?: number
|
||||
activeTransition?: string
|
||||
inactiveTransition?: string
|
||||
wrapperClassName?: string
|
||||
innerClassName?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
padding: 100,
|
||||
disabled: false,
|
||||
magnetStrength: 2,
|
||||
activeTransition: 'transform 0.3s ease-out',
|
||||
inactiveTransition: 'transform 0.5s ease-in-out',
|
||||
wrapperClassName: '',
|
||||
innerClassName: ''
|
||||
})
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false
|
||||
})
|
||||
|
||||
const magnetRef = ref<HTMLDivElement | null>(null)
|
||||
const isActive = ref(false)
|
||||
const position = ref({ x: 0, y: 0 })
|
||||
|
||||
const transitionStyle = computed(() =>
|
||||
isActive.value ? props.activeTransition : props.inactiveTransition
|
||||
)
|
||||
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
if (!magnetRef.value || props.disabled) return
|
||||
|
||||
const { left, top, width, height } = magnetRef.value.getBoundingClientRect()
|
||||
const centerX = left + width / 2
|
||||
const centerY = top + height / 2
|
||||
|
||||
const distX = Math.abs(centerX - e.clientX)
|
||||
const distY = Math.abs(centerY - e.clientY)
|
||||
|
||||
if (distX < width / 2 + props.padding && distY < height / 2 + props.padding) {
|
||||
isActive.value = true
|
||||
const offsetX = (e.clientX - centerX) / props.magnetStrength
|
||||
const offsetY = (e.clientY - centerY) / props.magnetStrength
|
||||
position.value = { x: offsetX, y: offsetY }
|
||||
} else {
|
||||
isActive.value = false
|
||||
position.value = { x: 0, y: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('mousemove', handleMouseMove)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('mousemove', handleMouseMove)
|
||||
})
|
||||
|
||||
watch(() => props.disabled, (newDisabled) => {
|
||||
if (newDisabled) {
|
||||
position.value = { x: 0, y: 0 }
|
||||
isActive.value = false
|
||||
}
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user