
不用React也能用morphicons纯JavaScript图标形变驱动完全手册手势拖拽逐帧scrubbing详解【免费下载链接】morphiconsAny icon morphs into any other — universal morphing for stroke-based icons with spring physics. Zero dependencies, ~7 KB gzip.项目地址: https://gitcode.com/gh_mirrors/mo/morphiconsmorphicons 是一个零依赖、gzip 约 7 KB 的通用图标形变库任意描边图标都能形变为任意其他图标旋转由数学自动推导而不是人工声明。很多人以为它只服务 React/Vue/Svelte其实它的根是一个纯 JavaScript 的图标形变驱动createMorph入口morphicons/dom源码见 src/dom/index.ts——不依赖任何框架直接驱动一个path元素特别适合做手势拖拽和逐帧 scrubbing。本文就是这个纯 JS 驱动的完全手册。 快速安装与导入morphicons 只发布 ESM任何现代构建工具Vite、esbuild、Rollup都能直接消费bun add morphicons # 或 npm install / pnpm add图标数据来自数据包如 vanilla 版lucide而不是组件包——驱动消费的是IconNode结构或原始d字符串import { createMorph } from morphicons/dom; import { Menu, X } from lucide; // 数据不是组件 const pathEl document.querySelector(path); const m createMorph(pathEl, Menu); m.morphTo(X, snappy); // 带弹簧物理地飞向 X m.set(Menu); // 不带动画直接跳到 Menu就这么简单状态在你手里动画只是驱动的一个实现细节。 三种驱动 API 一览createMorph返回的Morph句柄只有 6 个成员定义见 src/dom/index.ts记住下面这张表就够用API作用是否走弹簧典型场景morphTo(icon, spring?)形变到目标图标✅ 可中断点击切换菜单/关闭set(icon)瞬间跳到目标❌初始化、复位seek(icon, t)冻结在 t 帧t ∈ [0,1]❌scrubbing、手势m.progress t对当前目标 seek 的语法糖❌拖拽进度条m.reducedMotion动效降级策略—无障碍适配m.destroy()注销实例—卸载时清理1. 弹簧预设怎么选spring参数支持三个内置预设数值定义在 src/core/spring.ts预设刚度 k阻尼 c手感smooth17026临界阻尼零过冲稳snappy42030快带一点点过冲默认推荐bouncy30014过冲明显俏皮也可以传{ stiffness, damping }自定义。弹簧是一个阻尼谐振子源码 src/core/spring.ts用半隐式欧拉以 1/240 秒子步积分稳定且只需约 25 行代码不引入任何动画库。2. 可中断性连点狂点都不会跳帧morphicons 的morphTo是真正可中断的飞行中再次调用时它从当前中间形状重新规划路径同时保留弹簧速度见 src/dom/index.ts 的snapshot/retarget逻辑。视觉运动连续不断连点只会让图标更活不会瞬移。 逐帧 scrubbingseek 与 progress 详解scrubbing逐帧擦洗是手势交互的核心不用弹簧图标完全跟随你的手指。m.seek(X, 0.4); // from当前形状, toX, 冻结在 40% 帧 m.progress 0.4; // 等价于 seek(当前目标, 0.4)seek的底层原理src/dom/index.ts停表先注销弹簧 ticker并把速度清零——受控模式不继承任何速度复用计划如果目标图标没变icon target且已有飞行计划直接复用缓存的 plan零成本重渲染定点渲染调用核心的极坐标插值interpPolar把 t 直接算到第 t 帧写一次d属性就收工不启动任何循环。这意味着 scrubbing 的开销是一次插值 一次字符串拼接非常适合 60fps 连续调用。✋ 手势拖拽完整示例手指滑多远图标变多少下面是一个完整的指针拖拽示例图标在菜单 ↔ 关闭之间形变进度完全由拖拽位置决定松手后按过半阈值自动弹回或定型svg width48 height48 viewBox0 0 24 24 fillnone strokecurrentColor stroke-width2 stroke-linecapround path idi/path /svgimport { createMorph } from morphicons/dom; import { Menu, X } from lucide; const el document.querySelector(#i); const m createMorph(el, Menu); let dragging false; let startY 0; let startT 0; // 拖拽开始时的进度 el.setPointerCapture?.(0); // 容器上监听指针事件同理 window.addEventListener(pointerdown, (e) { dragging true; startY e.clientY; startT currentT; }); window.addEventListener(pointermove, (e) { if (!dragging) return; // 每移动 120px 推进一个完整进度clamp 到 [0, 1] const t Math.min(1, Math.max(0, startT (e.clientY - startY) / 120)); m.progress t; // 逐帧 scrubbing冻结渲染无弹簧 currentT t; }); window.addEventListener(pointerup, () { dragging false; // 松手过半定型为 X否则弹回 Menu走弹簧带惯性感 if (currentT 0.5) m.morphTo(X, snappy); else m.morphTo(Menu, snappy); });要点拖拽中用progress/seek冻结帧零延迟跟随松手后用morphTo弹簧收尾从当前中间形状起飞所以没有任何跳变seek结束后调morphTo是被官方支持的衔接方式——中间形状就是合法的形变源。 同样的冻结对 进度模型就是 React/Vue/Svelte 绑定里受控模式from/to/progress三个 props的底层五种绑定共享同一套生命周期契约实现见 src/dom/controller.ts。️ 没有 SVG 节点Canvas 与 CSS mask 适配器morphicons 对外只有两个结构契约入口的IconInput出口的PathEl任何有setAttribute的对象。基于这个契约morphicons/adapters提供三个格式适配器纯 JS 环境同样适用svgToIcon把 SVG 标记Iconify body、网页里复制的svg、shadcn 注册表的path d转成任意入口都接受的IconInput。在模块作用域解析一次即可plan 缓存就始终有效源码 src/adapters/svg.ts。maskTarget你的图标是 UnoCSS/Iconify 的 CSS maskDOM 里没有path时它创建一对隐藏 mask 缓冲并把手柄交给createMorph元素原地形变src/adapters/mask.ts。canvasTarget图标直接变成像素每帧一次stroke(new Path2D(d))可跑在OffscreenCanvas Worker 里甚至导出为 PNG、录制成视频src/adapters/canvas.ts。三个适配器就是createMorph——只是写入目标不同弹簧、中断、reduced motion 行为完全一致。⚡ 性能为什么可以疯狂调用来自 README.md 的实测数据解释了为什么 scrubbing 可以无节制使用计划构建亚毫秒plan(A, B)重采样 匹配 2D Procrustes 对齐实测 0.01–0.06 ms每帧零数值分配插值器直接写入 plan 预分配的Float64Array每帧唯一的新分配是d字符串按引用缓存normalize/plan用WeakMap缓存Lucide 的稳定 import 引用天然命中src/dom/index.ts一个全局 rAF所有实例共享单例调度器一百个图标同时形变也只有 1 个动画循环全部静止时 rAF 自动停止src/dom/index.ts。♿ 无障碍与细节reducedMotion 策略图标形变属于小、短、有沟通意图的微动效所以默认never总是播放如果你的 App 必须严格跟随系统减少动态效果设置显式开启const m createMorph(el, Menu, { reducedMotion: user }); m.reducedMotion user; // 也可运行时切换对下一次 morphTo 生效never默认忽略 OS 设置总是动画user系统开启减少动效时morphTo退化为瞬间切换always永远直跳适合截图与自动化测试。 不用 ES 模块 / 要 SSR还有morph-iconWeb Componentmorphicons/element提供morph-icon自定义元素源码 src/element/index.ts它是第五种绑定而非第二套实现暴露同样的三种模式适合纯 HTML、HTMX、Rails 等服务端渲染栈script typemodule import { defineMorphIcon } from morphicons/element; defineMorphIcon(); // 幂等也可自定义标签名 /script !-- 属性接收 d 字符串属性properties接收完整 IconInput -- morph-icon iconM4 6h16M4 12h16M4 18h16 labelMenu/morph-icon在脚本里对元素直接调用el.morphTo(X)命令式、el.icon X非受控、el.progress 0.5受控 scrubbing即可。Astro 项目则直接用它的 SSR 外壳 src/astro/MorphIcon.astro服务端输出精确的静态 SVG零闪烁、零布局偏移水合只是自定义元素升级。✅ 上手清单TL;DR装库bun add morphicons图标用数据包vanillalucide等建驱动createMorph(pathEl, 初始图标)卸载时m.destroy()切换m.morphTo(X, snappy)——可中断、保留速度跳转m.set(icon)——初始化与复位scrubbingm.progress t或m.seek(to, t)——手势/滚动逐帧跟随松手再morphTo收尾无障碍需要跟随系统设置时传reducedMotion: user。想亲手把玩仓库自带 playground38 个真实图标、逐对显示检测到的相似变换、t 滑杆在仓库根目录执行bun run play即可启动代码在 playground/main.ts。更多架构细节可阅读 README.md 与 docs/adr/ 下的决策记录。【免费下载链接】morphiconsAny icon morphs into any other — universal morphing for stroke-based icons with spring physics. Zero dependencies, ~7 KB gzip.项目地址: https://gitcode.com/gh_mirrors/mo/morphicons创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考