Axi's Blog
如何在 Astro 中为你的鼠标添加指针动画Blur image

前言#

这篇博客会简单讲解一下如何在 Astro 中为你的鼠标添加指针动画。

方法#

在 Astro 中,Layout 这个概念非常重要。无论你的 Layout 如何设计,一般来说都会通过 <slot /> 来支持内容的插入,并且一般的全部界面最终都会在 <BaseLayout /> 中被包裹。

因此假如你想要添加一些全局效果,都可以编辑 src/layouts/BaseLayout.astro 文件。

对于指针效果来说,你可以在添加:

src/layouts/BaseLayout.astro
...
  <body class='flex justify-center bg-background'>
    <style define:vars={{ highlightColor }}>
      ...

      /* 点击粒子效果样式 */
      :global(.click-particle) {
        position: fixed;
        pointer-events: none;
        width: 14px;
        height: 14px;
        border-radius: 50%;
        z-index: 9999;
        animation: particle-explosion 1.1s ease-out forwards;
        box-shadow: 0 0 6px rgba(255, 255, 255, 0.8);
      }

      /* 暗色主题下的粒子效果 */
      :global(.dark .click-particle) {
        box-shadow: 0 0 8px rgba(255, 255, 255, 0.4);
      }

      @keyframes particle-explosion {
        0% {
          opacity: 1;
          transform: scale(0.4) translate(0, 0);
        }
        15% {
          opacity: 1;
          transform: scale(1.3) translate(var(--dx), var(--dy));
        }
        60% {
          opacity: 0.8;
          transform: scale(1) translate(calc(var(--dx) * 2.5), calc(var(--dy) * 2.5));
        }
        100% {
          opacity: 0;
          transform: scale(0.3) translate(calc(var(--dx) * 3.5), calc(var(--dy) * 3.5));
        }
      }

      /* 亮色主题粒子颜色 */
      :global(.click-particle.color-1) {
        background: #ffc1cc;
        background: radial-gradient(circle, #ffb3ba 0%, #ffc1cc 100%);
      }

      :global(.click-particle.color-2) {
        background: #bde4ff;
        background: radial-gradient(circle, #a8d8ff 0%, #bde4ff 100%);
      }

      :global(.click-particle.color-3) {
        background: #fff2a8;
        background: radial-gradient(circle, #ffe66d 0%, #fff2a8 100%);
      }

      :global(.click-particle.color-4) {
        background: #e6ccff;
        background: radial-gradient(circle, #d4a5ff 0%, #e6ccff 100%);
      }

      :global(.click-particle.color-5) {
        background: #c1ffc1;
        background: radial-gradient(circle, #a8e6a8 0%, #c1ffc1 100%);
      }

      :global(.click-particle.color-6) {
        background: #ffd4a3;
        background: radial-gradient(circle, #ffcc99 0%, #ffd4a3 100%);
      }

      :global(.click-particle.color-7) {
        background: #c4e8ff;
        background: radial-gradient(circle, #b3deff 0%, #c4e8ff 100%);
      }

      :global(.click-particle.color-8) {
        background: #f8d7da;
        background: radial-gradient(circle, #f5c2c7 0%, #f8d7da 100%);
      }

      :global(.click-particle.color-9) {
        background: #d1f2d1;
        background: radial-gradient(circle, #c3e6c3 0%, #d1f2d1 100%);
      }

      :global(.click-particle.color-10) {
        background: #fff0d4;
        background: radial-gradient(circle, #ffe8b3 0%, #fff0d4 100%);
      }

      /* 暗色主题粒子颜色 - 更深更鲜艳 */
      :global(.dark .click-particle.color-1) {
        background: #ff6b8a;
        background: radial-gradient(circle, #ff4757 0%, #ff6b8a 100%);
      }

      :global(.dark .click-particle.color-2) {
        background: #4fc3f7;
        background: radial-gradient(circle, #29b6f6 0%, #4fc3f7 100%);
      }

      :global(.dark .click-particle.color-3) {
        background: #ffd54f;
        background: radial-gradient(circle, #ffca28 0%, #ffd54f 100%);
      }

      :global(.dark .click-particle.color-4) {
        background: #ba68c8;
        background: radial-gradient(circle, #ab47bc 0%, #ba68c8 100%);
      }

      :global(.dark .click-particle.color-5) {
        background: #81c784;
        background: radial-gradient(circle, #66bb6a 0%, #81c784 100%);
      }

      :global(.dark .click-particle.color-6) {
        background: #ffb74d;
        background: radial-gradient(circle, #ffa726 0%, #ffb74d 100%);
      }

      :global(.dark .click-particle.color-7) {
        background: #64b5f6;
        background: radial-gradient(circle, #42a5f5 0%, #64b5f6 100%);
      }

      :global(.dark .click-particle.color-8) {
        background: #f48fb1;
        background: radial-gradient(circle, #f06292 0%, #f48fb1 100%);
      }

      :global(.dark .click-particle.color-9) {
        background: #a5d6a7;
        background: radial-gradient(circle, #81c784 0%, #a5d6a7 100%);
      }

      :global(.dark .click-particle.color-10) {
        background: #ffe082;
        background: radial-gradient(circle, #ffd54f 0%, #ffe082 100%);
      }
    </style>

    ...
    <script>
      document.addEventListener('DOMContentLoaded', () => {
        function createParticle(
          x: number,
          y: number,
          angle: number,
          distance: number,
          colorIndex: number
        ) {
          const particle = document.createElement('div')
          particle.className = `click-particle color-${colorIndex}`
          const dx = Math.cos(angle) * distance
          const dy = Math.sin(angle) * distance
          particle.style.setProperty('--dx', dx + 'px')
          particle.style.setProperty('--dy', dy + 'px')
          particle.style.left = x + 'px'
          particle.style.top = y + 'px'
          const size = Math.random() * 6 + 8
          particle.style.width = size + 'px'
          particle.style.height = size + 'px'
          document.body.appendChild(particle)
          setTimeout(() => {
            if (particle.parentNode) {
              particle.parentNode.removeChild(particle)
            }
          }, 1100)
        }
        document.addEventListener('click', (e) => {
          const particleCount = 10
          const baseDistance = 18
          for (let i = 0; i < particleCount; i++) {
            const angle = ((Math.PI * 2) / particleCount) * i
            const distance = baseDistance + Math.random() * 8
            const colorIndex = (i % 10) + 1
            setTimeout(() => {
              createParticle(e.clientX, e.clientY, angle, distance, colorIndex)
            }, i * 12)
          }
          for (let i = 0; i < 4; i++) {
            const randomAngle = Math.random() * Math.PI * 2
            const randomDistance = baseDistance + Math.random() * 10
            const colorIndex = Math.floor(Math.random() * 10) + 1
            setTimeout(
              () => {
                createParticle(e.clientX, e.clientY, randomAngle, randomDistance, colorIndex)
              },
              (particleCount + i) * 12
            )
          }
        })
      })
    </script>
  </body>
</html>
astro
如何在 Astro 中为你的鼠标添加指针动画
https://axi404.top/blog/cursor-feature
Author 阿汐
Published at October 11, 2025
Comment seems to stuck. Try to refresh?✨