照片墙太死板?做一个会随风摇摆的绳串图片交互效果

说在前面

大家平时做图片展示,很多都是卡片平铺、瀑布流、轮播图。 这次我们换个思路:把图片"挂"在一根绳子上,加上随风摆动的动态效果,支持拖拽拉扯回弹。

在线体验

codePen

codepen.io/yongtaozhen...

码上掘金

code.juejin.cn/pen/7634497...

关键代码

1、场景分层

Canvas 画绳子,DOM 放照片

  1. canvas#ropeCanvas:只负责画绳子。
  2. #photos:绝对定位的图片元素层。
  3. .controls:风力滑块控制区。
html 复制代码
<canvas id="ropeCanvas"></canvas>
<div id="photos"></div>
<div class="controls">...</div>

这么拆的好处是:绳子可以高频重绘,图片继续保留 DOM 的 3D transform 和 pointer 交互能力,性能和开发体验都更稳。

2、绳子曲线

线性插值 + 抛物线下垂

绳子不是死直线,而是通过参数 t(0~1)取点:

javascript 复制代码
function ropeAnchorPoint(t) {
  const lineX = lerp(ropeStart.x, ropeEnd.x, t);
  const lineY = lerp(ropeStart.y, ropeEnd.y, t);
  const arc = 4 * t * (1 - t);
  return {
    x: lineX + ropeSway * arc + dragX * (0.36 + 0.64 * arc),
    y: lineY + ropeSag * arc + dragY * (0.36 + 0.64 * arc),
  };
}

arc = 4t(1-t) 是关键,它在中点最大、两端最小,天然适合模拟"中间下垂、两端固定"的绳子形态。

3、照片摆动

弹簧阻尼模型做"钟摆感"

每张图都有自己的 angle(角度)和 velocity(角速度),每帧按受力更新:

javascript 复制代码
const acc =
  -p.stiffness * Math.sin(p.angle - p.restAngle) -
  p.damping * p.velocity +
  scaledWind;
p.velocity += acc * dt;
p.angle += p.velocity * dt;

这里本质是"回复力 + 阻尼 + 风力扰动"。 不同图片还带随机 phasemass,所以摇摆不会完全同步,看起来就更像真实挂件。

4、拖拽联动

限制位移 + 弹性回归

拖拽不是直接把图片瞬移,而是把拖拽位移转成"绳子的外力输入":

javascript 复制代码
const len = Math.hypot(dx, dy);
const dragLimit = 110;
if (len > dragLimit) {
  const ratio = dragLimit / len;
  dx *= ratio;
  dy *= ratio;
}

然后再通过速度与阻尼平滑回弹:

javascript 复制代码
dragVX += (dragTargetX - dragX) * dragK * dt;
dragVX *= Math.exp(-dragDamping * dt);
dragX += dragVX * dt;

5、视觉细节

绳子高光 + 穿绳遮挡 + 透视倾斜

这个效果需要注意一些细节:

  1. 绳子画两遍:粗深色主线 + 细浅色高光线。
  2. 每张图上方加 .rope-pass,并按切线角度旋转,制造"绳子穿过卡片孔位"的假象。
  3. 图片 transform 叠加 rotateZ + rotateY + rotateX,速度越大越有轻微俯仰感。
javascript 复制代码
const tangent = ropeTangent(p.t);
const tangentAngle = Math.atan2(tangent.y, tangent.x);
p.passEl.style.transform = `translate(0, -50%) rotate(${tangentAngle}rad)`;

源码地址

gitee

gitee.com/zheng_yongt...

github

github.com/yongtaozhen...

🌟 觉得有帮助的可以点个 star~

🖊 有什么问题或错误可以指出,欢迎 pr~

📬 有什么想要实现的功能或想法可以联系我~

公众号

关注公众号『 前端也能这么有趣 』,获取更多有趣内容。

发送 加群 还可以加入群聊,一起来学习(摸鱼)吧~

说在后面

🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。

相关推荐
竹林8185 小时前
用 wagmi v2 + WebSocket 硬磕 NFT 上架失败:一个前端开发者踩过的实时状态同步坑
javascript·next.js
豹哥学前端5 小时前
告别割裂式学习:待办清单项目,一次性掌握数组、本地存储与事件委托
前端·javascript
2501_915921435 小时前
HTTPS前端劫持 新一代流量劫持解决方案
前端·网络协议·ios·小程序·https·uni-app·iphone
Yue栎廷5 小时前
邪修:Markdown加粗语法**本土化改造
前端·javascript·人工智能
爱怪笑的小杰杰5 小时前
优化 UniApp 日历组件的多语言切换:告别 setLocale 引起的 App 重启
java·前端·uni-app
有所事事5 小时前
如何让AI写代码越写越像你
前端·后端
Allen正心正念20255 小时前
前端——Node.js&npm,学点前端的东西
前端·npm·node.js
西瓜有点饿5 小时前
前端基础知识之---Content-Type有哪些格式
前端
小歪 | 前端5 小时前
VUE_运行Vue项目Network: unavailable问题解决
前端·javascript·vue.js