磁吸按钮

按钮会向指针方向倾斜,文字移动得更多一些;指针离开后再平稳回位。

  • GSAP
  • 按钮
  • 跟随指针
  • 收录于

AI 提示词

使用 GSAP 为 React 按钮制作磁吸悬停效果。用一个约 40px 内边距的透明感应区包住按钮。指针在感应区内移动时,计算指针相对按钮中心的偏移,用 gsap.to 让按钮向指针方向移动偏移量的 35%,内部文字再额外移动 15%(duration 0.4,ease "power3.out")。指针离开时,用 0.6 秒的 "expo.out" 让两者回到 x: 0、y: 0。只对 transform 做动画。当用户开启 prefers-reduced-motion 时完全不启用此效果。按钮文字为“立即开始”。

源代码

Demo.tsx
'use client'

import gsap from 'gsap'
import s from './demo.module.css'

export default function MagneticButton({ labels }: { labels: Record<string, string> }) {
  const reduced = () => window.matchMedia('(prefers-reduced-motion: reduce)').matches

  const onMove = (e: React.PointerEvent<HTMLDivElement>) => {
    if (reduced()) return
    const button = e.currentTarget.firstElementChild as HTMLElement
    const r = button.getBoundingClientRect()
    const x = e.clientX - r.left - r.width / 2
    const y = e.clientY - r.top - r.height / 2
    gsap.to(button, { x: x * 0.35, y: y * 0.35, duration: 0.4, ease: 'power3.out' })
    gsap.to(button.firstElementChild, { x: x * 0.15, y: y * 0.15, duration: 0.4, ease: 'power3.out' })
  }

  const onLeave = (e: React.PointerEvent<HTMLDivElement>) => {
    const button = e.currentTarget.firstElementChild as HTMLElement
    gsap.to([button, button.firstElementChild], { x: 0, y: 0, duration: 0.6, ease: 'expo.out' })
  }

  return (
    <div className={s.zone} onPointerMove={onMove} onPointerLeave={onLeave}>
      <button type="button" className={s.button}>
        <span className={s.label}>{labels.cta}</span>
      </button>
    </div>
  )
}
demo.module.css
.zone {
  padding: 40px;
}

.button {
  display: inline-flex;
  align-items: center;
  height: 52px;
  padding: 0 28px;
  border: 0;
  border-radius: 999px;
  background: var(--stage-ink);
  color: var(--stage-bg);
  font: 500 var(--text-base) / 1 var(--font-body);
  white-space: nowrap;
  cursor: pointer;
  will-change: transform;
}

.button:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 3px;
}

.label {
  display: inline-block;
  will-change: transform;
}

投稿创意

看到想收录的动效或主题?简单描述一下,会打开一个预先填好的 GitHub Issue,确认后即可提交。

你想投稿的是?

需要 GitHub 账号,投稿内容会公开。