wired-elements 的 wired-spinner 手绘风加载指示器:API 详解与源码级动画原理

发布时间:2026/9/23 16:45:06
wired-elements 的 wired-spinner 手绘风加载指示器:API 详解与源码级动画原理 wired-elements 的 wired-spinner 手绘风加载指示器API 详解与源码级动画原理【免费下载链接】wired-elementsCollection of custom elements that appear hand drawn. Great for wireframes or a fun look.项目地址: https://gitcode.com/gh_mirrors/wi/wired-elementswired-spinner 是 wired-elements 组件库中一个手绘素描风的加载指示器loading spinner用于展示进度或任务进行中的状态。本文以 docs/wired-spinner.md 为主线结合 src/wired-spinner.ts 源码与 examples/spinner.html 示例完整讲解其安装、HTML 用法、两个核心属性spinning、duration以及 CSS 着色方式并深入剖析其基于 SVG 与requestAnimationFrame的动画实现原理帮助你既能快速上手也能理解其内部机制。组件简介wired-spinner是一个继承自WiredBase的 Web Component自定义元素渲染为一个 76×76 的 SVG 画布外圈是一个粗糙手绘风格的椭圆描边内部是一个通过斜线填充hachure绘制的小旋钮knob旋钮沿椭圆轨道匀速旋转形成加载动画。它的定位是给线框图wireframe或趣味界面提供一个符合整体手绘风格的加载反馈。完整的 wired-elements 组件集合与在线演示可在 wiredjs.com 查看本组件与库内其他元素如 wired-button、wired-progress配合使用效果最佳。安装与引入方式一npm 安装推荐在你的 JavaScript 项目中安装 wired-elements 包npm i wired-elements然后在代码中按需导入模块两种写法等价均从包名导出import { WiredSpinner } from wired-elements; // 或 import { WiredSpinner } from wired-elements/lib/wired-spinner.js;第一种写法利用 src/wired-elements.ts 中的统一出口export * from ./wired-spinner批量导入第二种写法直接指向单文件模块适合只想引入单个组件、减小打包体积的场景。当前仓库package.json声明版本为3.0.0-rc.7采用 ESMtype: module依赖litv2 系列与roughjsv4.3.1请确保你的构建工具支持 ES Modules 与自定义元素。方式二CDN 直接加载不经过构建工具时可以在 HTML 中通过script typemodule直接加载script typemodule srchttps://unpkg.com/wired-elements/lib/wired-spinner.js?module/script方式三本地构建后引用仓库根目录执行npm run build即rm -rf lib tsc见 package.json后会生成lib/目录示例页面 examples/spinner.html 便是这样引用本地产物的script typemodule src../lib/wired-spinner.js/script基本用法在 HTML 中直接书写wired-spinner标签即可wired-spinner idsp/wired-spinner wired-spinner spinning duration1000/wired-spinner第一个 spinner 未设置任何属性默认静止spinning默认为false只显示一个手绘椭圆环与静态旋钮。第二个 spinner 设置了spinning布尔属性HTML 中布尔属性只要出现即为true与duration1000因此会以每圈 1000ms 的速度旋转。交互示例点击按钮切换旋转状态参考 examples/spinner.html可以用一个按钮动态切换spinning属性wired-spinner idsp/wired-spinner wired-buttonToggle/wired-button script document.querySelector(wired-button).addEventListener(click, () { const sp document.getElementById(sp); sp.spinning !sp.spinning; }); /script由于spinning是响应式属性见下文属性表直接通过 JavaScript 修改sp.spinning即可驱动动画启停无需手动操作 DOM。属性Propertieswired-spinner 只有两个对外属性均定义在 src/wired-spinner.ts属性类型默认值说明spinningBooleanfalse是否处于旋转状态。为true时启动动画为false时停止。durationNumber1500完成一整圈旋转所需的时间毫秒。spinning 的响应式行为源码中通过property({ type: Boolean }) spinning false;声明并在生命周期钩子updated()中监听updated() { super.updated(); if (this.spinning) { this.startSpinner(); } else { this.stopSpinner(); } }也就是说只要spinning变为true组件立即调用startSpinner()重置计时并从第 0 帧开始旋转变为false时调用stopSpinner()取消动画帧。因此同一时刻只会有一个动画循环在运行反复切换也不会叠加多个定时器startSpinner()内部先调用stopSpinner()做防重入处理。duration 的作用边界duration表示旋钮走完一整圈旋转 360°的毫秒数数值越小转速越快。需要说明的是它只影响旋转速度不改变旋钮的轨道半径、组件尺寸或椭圆形状即使duration设置为 0单圈耗时也会被钳制在至少一帧value通过Math.min(1, ...)截断内完成。从源码看duration未设置上下限校验请按实际需要传入合理的正整数。样式定制wired-spinner 的配色非常简单修改元素自身的color样式即可改变其颜色。wired-spinner { color: red; /* 手绘描边与旋钮将变为红色 */ } wired-spinner.custom { color: #2c7be5; /* 也可以按类名单独指定 */ }这一机制依赖于 src/wired-base.ts 中的BaseCSSpath { stroke: currentColor; ... }以及 src/wired-spinner.ts 内的组件样式。组件内所有path的描边颜色均取currentColor因此只需覆盖color即可整体换色外圈椭圆描边stroke-opacity: 0.65、stroke-width: 1.5营造淡而细腻的手绘笔触旋钮.knob类stroke-width: 2.8、stroke-opacity: 1比外圈更粗更实突出旋转主体组件宿主display: inline-block; position: relative便于在文档流中内联布局。color支持任何合法的 CSS 颜色值例如#ff6600、rgb(...)、var(--primary)等。除此之外组件不暴露尺寸属性画布固定为 76×76见 src/wired-spinner.ts 的canvasSize()返回值如需缩放可对宿主元素使用 CSStransform: scale(...)。源码级原理解析1. 绘制阶段椭圆环 斜线填充旋钮组件渲染逻辑为render()返回一个空svg真正的内容在draw()中绘制src/wired-spinner.tsprotected draw(svg: SVGSVGElement, size: Point) { ellipse(svg, size[0] / 2, size[1] / 2, Math.floor(size[0] * 0.8), Math.floor(0.8 * size[1]), this.seed); this.knob hachureEllipseFill(0, 0, 20, 20, this.seed); this.knob.classList.add(knob); svg.appendChild(this.knob); this.updateCursor(); }外圈调用 src/wired-lib.ts 的ellipse()圆心在 (38, 38)宽高约为画布的 80%约 60.8px通过 roughjs 生成带随机抖动的手绘感椭圆路径内部options()使用roughness: 1、bowing: 0.85、maxRandomnessOffset: 2等参数见 src/wired-lib.ts。旋钮调用hachureEllipseFill(0, 0, 20, 20, this.seed)src/wired-lib.ts生成一个 20×20、以斜线hachure填充的小椭圆挂上.knob类并追加到 SVG。seed每个实例在构造时都会生成一个随机seedMath.floor(Math.random() * 2 ** 31)见 src/wired-base.ts保证每个 spinner 的笔触抖动、填充疏密都是独一无二的手绘痕迹这也是所有 wired 元素每次都不一样的原因。draw()由WiredBase.wiredRender()统一驱动src/wired-base.ts当尺寸未变化时不会重复重绘首次渲染后会给宿主添加wired-rendered类把透明度从0过渡到1BaseCSS中:host { opacity: 0 }→:host(.wired-rendered) { opacity: 1 }实现柔和的淡入效果。2. 动画阶段requestAnimationFrame 驱动动画的核心在startSpinner()/stopSpinner()/nextTick()/tick()这组私有方法src/wired-spinner.tsprivate nextTick() { this.frame window.requestAnimationFrame((t) this.tick(t)); } private tick(t: number) { if (this.spinning) { if (!this.timerstart) this.timerstart t; this.value Math.min(1, (t - this.timerstart) / this.duration); this.updateCursor(); if (this.value 1) { this.value 0; this.timerstart 0; } this.nextTick(); } else { this.frame 0; } }运行逻辑nextTick()通过window.requestAnimationFrame注册下一帧回调并把句柄存入this.frametick(t)收到浏览器提供的时间戳t以首次回调时间作为timerstart用(t - timerstart) / duration计算本圈进度value范围 01updateCursor()根据value计算旋钮的新位置当value达到 1 时归零并重置计时起点开启下一圈从而实现无缝循环只要spinning仍为true就继续注册下一帧一旦为false循环自然终止this.frame 0。stopSpinner()则会立即调用window.cancelAnimationFrame(this.frame)取消尚未执行的帧保证停止响应即时生效。3. 旋钮定位极坐标圆周运动updateCursor()src/wired-spinner.ts用极坐标把旋钮放到椭圆轨道上const position: Point [ Math.round(38 25 * Math.cos(this.value * Math.PI * 2)), Math.round(38 25 * Math.sin(this.value * Math.PI * 2)) ]; this.knob.style.transform translate3d(${position[0]}px, ${position[1]}px, 0) rotateZ(${Math.round(this.value * 360 * 2)}deg);圆心 (38, 38)轨道半径 25pxvalue从 0 到 1 对应角度 0 到 2πMath.cos/Math.sin给出圆周上的坐标translate3d使用 GPU 合成层旋转过程顺滑同时叠加rotateZ(value * 720)让旋钮自身每圈额外自转 720°两圈强化滚动的视觉动感动画是纯 CSStransform更新不触发回流/重排性能友好。4. 与 wired-elements 体系的协作wired-spinner通过customElement(wired-spinner)注册src/wired-spinner.ts并与其他组件一同从 src/wired-elements.ts 统一导出。它复用了WiredBase的canvasSize/draw抽象与seed机制是理解整个 wired 手绘体系roughjs 绘制 lit 响应式 随机 seed的最佳入门组件之一同类的进度类组件还有 wired-progress 与 wired-progress-ring可对比阅读。常见问题与提示为什么我的 spinner 不动默认spinning为false请确认已设置spinning属性或通过 JS 将sp.spinning置为true同时确认脚本为typemodule且组件已正确加载未加载成功时自定义元素不会被注册。如何调整速度修改duration属性即可单位为毫秒默认 1500ms/圈duration1000比默认快约 1/3。如何换颜色设置colorCSS 属性例如wired-spinner { color: tomato; }。如何停止动画将spinning置为false组件会通过cancelAnimationFrame立即停止不会在后台空转消耗资源。结语wired-spinner以极简的 API两个属性 一个颜色样式提供了与 wired-elements 手绘风格完全统一的加载指示能力外圈手绘椭圆 斜线填充旋钮 圆周旋转动画。通过阅读 src/wired-spinner.ts 源码你还能复用其极坐标定位 requestAnimationFrame 循环 CSS transform 更新的动画范式为自己的组件实现类似的轻量动效。无论是快速搭建线框图原型还是为趣味界面补充加载反馈它都是一个开箱即用、风格统一的选择。【免费下载链接】wired-elementsCollection of custom elements that appear hand drawn. Great for wireframes or a fun look.项目地址: https://gitcode.com/gh_mirrors/wi/wired-elements创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考