概述
WindChime 是一个纯客户端 Vue 组件,模拟绳子悬挂的风铃效果。结构为:挂点 → 绳子 → 玻璃球 → 玻璃棍 → 卡片,支持拖拽交互、风力模拟和自定义卡片内容。
物理模型
组件使用摆锤链(pendulum chain)物理模型:
- 玻璃球:弹簧-阻尼绳悬挂,支持拖拽投掷
- 玻璃棍:通过摆锤力矩从球底部悬挂,具有转动惯量(滞后响应),弹性边界触顶反弹
- 卡片:通过短绳从棍底端悬挂,转动惯量比棍更大(明显滞后),同样具有弹性边界
棍子和卡片不是直接跟随球移动,而是通过力矩传递逐级响应——球位移 → 棍偏转 → 卡片偏转,产生真实的延迟和回荡效果。
使用示例
基础用法
vue
<template>
<div>
<h1>页面</h1>
<ClientOnly>
<WindChime />
</ClientOnly>
</div>
</template>带自定义参数和卡片内容
vue
<template>
<div>
<ClientOnly>
<WindChime
:rest-rope-length="180"
:ball-size="80"
ball-image="/images/crystal-ball.png"
:stick-length="60"
:anchor-offset-x="70"
:spring-constant="0.04"
:damping="0.96"
:enable-wind="true"
:wind-intensity="1.5"
>
<!-- 自定义卡片内容插槽 -->
<template #default>
<div style="text-align: center;">
<span style="font-size: 2rem;">🎋</span>
<p style="margin: 4px 0; color: #4a6741;">许愿签</p>
<p style="font-size: 0.7rem; color: #666;">心想事成</p>
</div>
</template>
</WindChime>
</ClientOnly>
</div>
</template>Props 详细说明
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
ballImage |
String | '' |
玻璃球内显示的图片 URL(可选) |
ballSize |
Number | 72 |
玻璃球直径,单位 px |
ballStyle |
Object | {} |
传递给玻璃球的额外 CSS 样式 |
stickLength |
Number | 50 |
玻璃棍高度,单位 px |
cardWidth |
Number | 90 |
卡片宽度,单位 px |
cardHeight |
Number | 120 |
卡片高度,单位 px |
cardBgColor |
String | 'rgba(255,255,255,0.92)' |
卡片背景色 |
restRopeLength |
Number | 160 |
静止时绳子长度(挂点到球顶部),单位 px |
anchorOffsetX |
Number | 50 |
挂点水平位置,视口宽度百分比(vw),50 即居中 |
anchorOffsetY |
Number | 25 |
挂点垂直位置,绳子起点距容器顶部的距离,单位 px |
positionMode |
String | 'absolute' |
定位模式:'absolute'(随页面滚动消失)或 'fixed'(始终固定) |
springConstant |
Number | 0.035 |
弹簧系数,越大回弹力越强、摆动越快 |
damping |
Number | 0.965 |
球阻尼系数(每帧速度保留率),越接近 1 摆动越久 |
gravity |
Number | 0.35 |
重力加速度,影响下垂程度 |
enableWind |
Boolean | true |
是否启用风吹效果 |
windIntensity |
Number | 1.0 |
风力强度倍数 |
zIndex |
Number | 1000 |
CSS z-index 层级 |
技术要点
- 纯客户端组件:依赖浏览器 DOM 和
requestAnimationFrame,务必用<ClientOnly>包裹,避免 SSR 报错 - 多实例支持:同一页面可放置多个
<WindChime>,调整anchorOffsetX避免重叠 - 插槽:卡片内容完全由默认插槽控制,支持任意 HTML 或 Vue 组件
- 性能:
requestAnimationFrame持续运行物理模拟,页面隐藏或销毁时自动停止 - TypeScript:组件使用
<script setup lang="ts">,函数参数含类型注解