Files
cloud-smart/src/directives/neuralCard.ts
2026-07-21 16:48:40 +08:00

127 lines
3.0 KiB
TypeScript

import type { Directive } from 'vue'
interface ActivatePoint {
id: number
x: number
y: number
progress: number
}
type NeuralCardElement = HTMLElement & {
_neuralAnimationId?: number | null
}
const vNeuralCard: Directive = {
mounted(el: HTMLElement) {
const neuralEl = el as NeuralCardElement
const points: ActivatePoint[] = []
let pointId = 0
let animationId: number | null = null
let isHovering = false
const createActivatePoint = () => {
const rect = el.getBoundingClientRect()
const edge = Math.floor(Math.random() * 4)
let x: number, y: number
switch (edge) {
case 0:
x = rect.left + Math.random() * rect.width
y = rect.top
break
case 1:
x = rect.right
y = rect.top + Math.random() * rect.height
break
case 2:
x = rect.left + Math.random() * rect.width
y = rect.bottom
break
default:
x = rect.left
y = rect.top + Math.random() * rect.height
}
points.push({
id: pointId++,
x,
y,
progress: 0
})
updateCSS()
}
const updateCSS = () => {
if (points.length === 0) {
el.style.setProperty('--neural-points', '')
return
}
const pointData = points
.map(p => `${p.x},${p.y},${p.progress}`)
.join('|')
el.style.setProperty('--neural-points', pointData)
el.style.setProperty('--neural-count', String(points.length))
}
const animate = () => {
points.forEach(p => {
p.progress += 0.02
})
const activePoints = points.filter(p => p.progress < 1)
points.length = 0
points.push(...activePoints)
updateCSS()
if (isHovering && points.length < 6) {
if (Math.random() > 0.7) {
createActivatePoint()
}
}
animationId = requestAnimationFrame(animate)
}
const handleMouseEnter = () => {
isHovering = true
el.classList.add('neural-active')
el.classList.add('neural-card-active')
}
const handleMouseLeave = () => {
isHovering = false
el.classList.remove('neural-active')
el.classList.remove('neural-card-active')
}
const handleMouseMove = (e: MouseEvent) => {
const rect = el.getBoundingClientRect()
const mouseX = ((e.clientX - rect.left) / rect.width) * 100
const mouseY = ((e.clientY - rect.top) / rect.height) * 100
el.style.setProperty('--mouse-x', `${mouseX}%`)
el.style.setProperty('--mouse-y', `${mouseY}%`)
}
el.addEventListener('mouseenter', handleMouseEnter)
el.addEventListener('mouseleave', handleMouseLeave)
el.addEventListener('mousemove', handleMouseMove)
animate()
neuralEl._neuralAnimationId = animationId
},
unmounted(el: HTMLElement) {
const neuralEl = el as NeuralCardElement
if (neuralEl._neuralAnimationId) {
cancelAnimationFrame(neuralEl._neuralAnimationId)
}
}
}
export default vNeuralCard