3D 球体画廊组件(斐波那契球面分布,拖拽惯性旋转可调)
3D 球体画廊组件:JS 斐波那契球面算法均匀分布 12-80 个卡片,Pointer Events 拖拽旋转带惯性滑动,数量、半径、自动旋转速度可调,自研实现零依赖零图片。
效果演示(真实可交互)
🖱 拖拽旋转球体,松手后惯性滑动;数量/半径/自转速度可调
完整代码
球面分布采用经典斐波那契球面算法:第 i 个点的竖直分量 y = 1 - (2i+1)/n,水平角 θ = 黄金角 × i,如此生成的分布比经纬网均匀得多,不会在极点扎堆。每个卡片的变换为 rotateY(方位角) rotateX(纬度) translateZ(半径)——先转到所在经度,再抬到所在纬度,最后沿半径方向推出,即落在球面上且法线朝外。
<div class="scene" id="scene">
<div class="sphere" id="sphere"></div>
</div>
.scene {
height: 440px; perspective: 1100px;
display: flex; align-items: center; justify-content: center;
cursor: grab; user-select: none; touch-action: none; /* 拖拽手感 */
}
.sphere {
position: relative; width: 0; height: 0;
transform-style: preserve-3d;
}
.item {
position: absolute; width: 76px; height: 76px;
margin-left: -38px; margin-top: -38px;
border-radius: 16px; display: flex; align-items: center; justify-content: center;
}
// 斐波那契球面分布
function build(n, R) {
sphere.innerHTML = '';
const golden = Math.PI * (3 - Math.sqrt(5));
for (let i = 0; i < n; i++) {
const y = 1 - (2 * i + 1) / n; // 竖直分量
const rad = Math.sqrt(Math.max(0, 1 - y * y)); // 纬度圈半径
const th = golden * i;
const az = Math.atan2(Math.cos(th) * rad, Math.sin(th) * rad) * 180 / Math.PI;
const pol = Math.asin(y) * 180 / Math.PI; // 纬度
const el = document.createElement('div');
el.className = 'item';
el.style.transform = `rotateY(${az}deg) rotateX(${pol}deg) translateZ(${R}px)`;
sphere.appendChild(el);
}
}
// 拖拽旋转 + 惯性
scene.addEventListener('pointerdown', e => { dragging = true; lastX = e.clientX; lastY = e.clientY; });
scene.addEventListener('pointermove', e => {
if (!dragging) return;
ry += (e.clientX - lastX) * 0.35;
rx -= (e.clientY - lastY) * 0.35;
vx = (e.clientX - lastX) * 0.35; // 记录速度 → 惯性
vy = -(e.clientY - lastY) * 0.35;
lastX = e.clientX; lastY = e.clientY;
apply();
});
scene.addEventListener('pointerup', () => dragging = false);
// rAF 循环:无拖拽时按惯性衰减并叠加自动旋转
参数说明
| 参数 | 位置 | 说明 |
|---|---|---|
| 卡片数量 | n | 12-80 个,斐波那契分布自动均匀排布 |
| 球体半径 | R | 卡片距球心的距离,演示中 100-220px 可调 |
| 自动旋转 | 循环中的 ry += speed·dt | 0-60°/s,拖拽时自动暂停 |
| 惯性衰减 | vx *= 0.94 | 系数越接近 1,松手后滑得越久 |
| 拖拽灵敏度 | * 0.35 | 光标位移到旋转角度的换算系数 |
兼容性与性能
- Pointer Events 统一处理鼠标与触屏,
touch-action: none防止触摸滚动干扰 - 旋转只改容器一个元素的 transform,内层卡片不参与逐帧计算,性能极佳
- 变换字符串仅在值变化时写入,避免无意义的样式重算
- 惯性速度逐帧指数衰减,松手后的滑动自然流畅
- Chrome / Safari / Firefox / Edge 全支持;iOS Safari 保留
-webkit-transform-style: preserve-3d - 斐波那契分布保证任意数量下卡片都均匀覆盖球面,不出现极点堆积
常见问题
Q: 卡片在极点附近扎堆或球面分布不均? 若用经纬网格均匀取角就会出现极点堆积;请改用斐波那契球面算法(本组件默认),其黄金角步进保证任意数量下分布均匀。
Q: 拖拽方向感觉反了? 旋转符号取决于个人手感偏好,交换 ry += 与 rx -= 的符号即可反转;vx/vy 需与拖拽方向同步调整,否则松手后惯性方向相反。
Q: 移动端拖拽时页面跟着滚动? 在场景元素上设置 touch-action: none(演示已含),并确认事件用的是 Pointer Events 而不是纯 mouse 事件。
Q: 可以商用吗? 可以。本组件为粤喵自研原创代码,免费商用无需署名,卡片内容、数量、配色均可自由定制。
许可与来源
- 许可证:自研原创 —— 粤喵自研原创,可免费用于个人与商业项目,无需署名。查看来源公示与许可清单
- 来源:粤喵团队原创自研(从效果思路到代码实现均为独立完成,未直接复制第三方代码)
- 首次发布:2026-09-01 · 最近更新:2026-09-01
- 修改日志:2026-09-01 首次发布;2026-09-13 补充许可证与来源标注、复制按钮说明与法务页入口
- 纠错:联系页面 / min@cactus.asia,2 个工作日内核实处理
常见问题
这个组件可以商用吗?
可以。本组件为粤喵自研原创,可免费用于个人和商业项目,无需署名。
浏览器兼容性如何?
支持所有现代浏览器(Chrome / Firefox / Safari / Edge 最新版本)。旧版 IE 不支持 CSS 动画相关特性。
怎么修改动画参数?
直接调整 CSS 中的 animation-duration(时长)、animation-timing-function(缓动曲线)等属性即可,代码中有注释说明。