模式 · 26
无限折返
Infinite wrap · infinite-wrap把有限的一排内容反复映射到视口附近,让拖动看不到头。
无限画廊不需要真的堆出无限张卡。每张卡根据滚动偏移选择离视口中心最近的周期副本;它跨周期跳位时,必须已经走出可见范围。周期太短,副本切换就会在眼前露出接缝。
公式
period = itemCount × spacing xᵢ = wrapCentered(i × spacing − offset, period) visible jump-free if period > viewport + item width
参数
| 本页默认 | 成熟实现 | |
|---|---|---|
| period | n × spacing | —决定同一张卡两份副本之间的距离。 |
| placement | wrapCentered | —始终选离中心最近的周期副本。 |
| offset | 拖拽累积值 | — |
怎样做好
- 先定周期,再算每张卡的位置。
wrapCentered能正确处理负偏移,原生%在负数一侧不够用。www-motion/rewrite/lib/case-runtime.js:4–5 - 把重定位点放到视口外:周期至少大于视口宽加一张卡宽。演示的短周期模式会直接露出跳位。www-motion/rewrite/lib/motion-kit.js:40–49
- 可以每帧重算最近副本,不必复制首尾节点再瞬移整个轨道。www-motion/rewrite/lib/motion-kit.js:40–49
在我们的案例里
27 个案例使用无限折返。dimension 的链式画廊采用首尾复制;重写库另提供 wrapNearest,让单个图块每帧选择最近副本。这两种实现解决的是同一条接缝。
出现在 27 个案例
参考实现 · basics.js
/**
* Position of item i on an endless strip scrolled by `offset`. Each item is drawn at the copy
* nearest the centre, so it jumps by one full period — make the period wider than the viewport
* plus one item, and the jump always happens off-screen.
*/
export const wrapPlacement = (i, n, offset, spacing) => wrapCentered(i * spacing - offset, n * spacing);
/** x folded into [0, period) — also for negative x, unlike `%`. */
export const wrap = (x, period) => ((x % period) + period) % period;
/** x folded into [-period/2, period/2): "how far from the centre copy". */
export const wrapCentered = (x, period) => wrap(x + period / 2, period) - period / 2;