mirror of
https://gitcode.com/leisileken/cloud-smart.git
synced 2026-09-11 10:27:20 +08:00
127 lines
3.0 KiB
TypeScript
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
|