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

0 阅读3分钟

说在前面

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

在线体验

codePen

codepen.io/yongtaozhen…

码上掘金

code.juejin.cn/pen/7634497…

image.png

关键代码

1、场景分层

Canvas 画绳子,DOM 放照片

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

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

2、绳子曲线

线性插值 + 抛物线下垂

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

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(角速度),每帧按受力更新:

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、拖拽联动

限制位移 + 弹性回归

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

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

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

dragVX += (dragTargetX - dragX) * dragK * dt;
dragVX *= Math.exp(-dragDamping * dt);
dragX += dragVX * dt;

5、视觉细节

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

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

  1. 绳子画两遍:粗深色主线 + 细浅色高光线。
  2. 每张图上方加 .rope-pass,并按切线角度旋转,制造“绳子穿过卡片孔位”的假象。
  3. 图片 transform 叠加 rotateZ + rotateY + rotateX,速度越大越有轻微俯仰感。
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,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。