- UI组件
- 前端
【免费下载链接】wired-elements
Collection of custom elements that appear hand drawn. Great for wireframes or a fun look.
wired-divider是 wired-elements 组件库中用于在页面区块之间绘制一条"手绘感"分割线的轻量级 Web Component。本文以 docs/wired-divider.md 为骨架,结合 源码实现 深入讲解它的安装方式、elevation属性、CSS 定制技巧以及底层基于 Rough.js 的绘制与响应式重绘机制,读完即可在 wireframe、原型草图或趣味风格页面中直接使用并自由调参。
组件简介:用一条手绘线划分内容区块
wired-divider在页面中渲染一条略带抖动、具有手绘笔触的水平分隔线,用于替代传统的<hr>,非常适合线框图(wireframes)、低保真原型(mockups)或任何追求"随手画"风格的界面。该组件自 2.0.0 版本(2019 年 10 月)加入 wired-elements(见 CHANGELOG.md),当前仓库包版本为 3.0.0-rc.7(见 package.json)。
组件本身不包含任何可见的 HTML 内容,而是通过自定义元素<wired-divider>在内部生成一个 SVG,再经由 Rough.js 的绘图算法输出带随机抖动的路径。它由 WiredDivider 类 实现,继承自WiredBase(src/wired-base.ts)。
安装与引入
通过 npm 安装
把 wired-elements 添加到你的 JavaScript 项目:
npm i wired-elements安装完成后即可从包入口导入WiredDivider:
import { WiredDivider } from 'wired-elements'; // 或者按需只加载单个组件: import { WiredDivider } from 'wired-elements/lib/wired-divider.js';两种方式都会注册<wired-divider>自定义元素。第一种方式经由包总入口 src/wired-elements.ts 一次性导出所有组件;第二种方式直接加载单个编译产物lib/wired-divider.js(lib目录由npm run build调用 TypeScript 编译生成,编译配置见 tsconfig.json)。
通过 CDN 直接引入
不经过打包工具时,可以在 HTML 页面中直接加载 ES Module:
<script type="module" src="https://unpkg.com/wired-elements/lib/wired-divider.js?module"></script>加载后,页面上所有<wired-divider>标签都会被自动升级为手绘分隔线组件。
在 HTML 中使用
最简单的用法是把<wired-divider>放在两个内容区块之间。原文档给出的示例:
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p> <wired-divider></wired-divider> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>仓库中提供了可直接运行的完整示例页面 examples/divider.html,它通过<script type="module" src="../lib/wired-divider.js"></script>引入本地构建产物,并用两段 Lorem ipsum 文本夹着一个<wired-divider></wired-divider>来演示效果。参照该示例,你的页面最小结构为:
<!DOCTYPE html> <html> <head> <script type="module" src="https://unpkg.com/wired-elements/lib/wired-divider.js?module"></script> </head> <body> <p>上方段落……</p> <wired-divider></wired-divider> <p>下方段落……</p> </body> </html>分隔线会自动撑满宿主元素(display: block)的可用宽度,并在组件首次渲染或容器尺寸变化时按当前宽度重新绘制。
属性详解:elevation
wired-divider只暴露一个属性:
| 属性 | 类型 | 取值范围 | 默认值 | 说明 |
|---|---|---|---|---|
elevation | Number | 1~5(含边界) | 1 | 绘制的手绘线条数 |
elevation表示组件绘制几条叠加的抖动线条。值为 1 时只画一条线;值越大线条越"浓重",视觉上像多层描边,可用作更强的视觉分隔强调。
<!-- 单条线(默认) --> <wired-divider></wired-divider> <!-- 双线分隔 --> <wired-divider elevation="2"></wired-divider> <!-- 五条线,最浓重 --> <wired-divider elevation="5"></wired-divider>从源码看,elevation是@property({ type: Number })声明的一个数字属性(src/wired-divider.ts#L8),并且超出 1~5 范围的值会被钳制。绘制与尺寸计算两处都执行了同样的钳制逻辑:
const elev = Math.min(Math.max(1, this.elevation), 5);也就是说,即使传入elevation="10"或elevation="0",实际绘制仍按 5 条或 1 条处理,而不是抛出错误。由于它是响应式属性,运行时通过 JS 修改也会触发重绘:
const divider = document.querySelector('wired-divider'); divider.elevation = 3; // 立即变为 3 条线自定义外观:颜色与线宽
组件遵循currentColor继承机制,因此通过 CSS 的color属性即可改变分隔线颜色,无需任何专属样式变量:
wired-divider { color: #b03060; /* 任意文字颜色都会作用于分隔线 */ }原因在基类样式 src/wired-base.ts#L24-L28 中:所有<path>均设置了stroke: currentColor;和stroke-width: 0.7;。如果希望更粗的笔触,可以直接覆盖路径样式:
wired-divider path { stroke-width: 1.5; }此外,基类样式还规定宿主元素默认opacity: 0,只有当组件完成首次绘制并加上wired-rendered类后才淡入显示(src/wired-base.ts#L6-L12),避免用户看到绘制前的空白或半成品闪烁。
源码原理:手绘线是如何画出来的
画布尺寸与线条布局
WiredDivider的重绘流程由基类WiredBase.wiredRender()驱动(src/wired-base.ts#L44-L59):先通过canvasSize()计算画布尺寸,再调用抽象方法draw()绘制。divider 的实现非常直观(src/wired-divider.ts#L30-L41):
protected canvasSize(): Point { const size = this.getBoundingClientRect(); const elev = Math.min(Math.max(1, this.elevation), 5); return [size.width, elev * 6]; } protected draw(svg: SVGSVGElement, size: Point) { const elev = Math.min(Math.max(1, this.elevation), 5); for (let i = 0; i < elev; i++) { line(svg, 0, (i * 6) + 3, size[0], (i * 6) + 3, this.seed); } }可以拆解出几个关键结论:
- 高度公式:画布高度 =
elevation × 6像素,即每条线占用 6px 的纵向空间; - 线条位置:第
i条线(从 0 开始)绘制在纵向i * 6 + 3处,正好落在每个 6px 条带的垂直居中位置; - 横向贯穿:每条线从 x=0 画到 x=容器宽度,因此分隔线始终占满可用宽度;
- 画布宽度自适应:宽度来自
getBoundingClientRect(),所以无论容器如何变化,线条都会重新铺满。
抖动效果来自 Rough.js
line()函数在 src/wired-lib.ts#L100-L102 中定义,它调用 Rough.js 的roughLine渲染器生成 SVG path。Rough.js 的随机参数在 src/wired-lib.ts#L32-L54 统一配置:
roughness: 1(抖动程度)bowing: 0.85(弯曲程度)maxRandomnessOffset: 2(随机偏移上限)stroke: '#000'、strokeWidth: 1.5(作为绘制参数,最终呈色仍受currentColor影响)
正因为 Rough.js 引入了随机偏移,画出的线不是笔直的标准线段,而是带着轻微毛边与弯曲的"手绘感"线条。
随机种子:每次都是独一无二的"手写体"
每个组件实例在创建时都会生成一个随机种子(src/wired-base.ts#L38):
protected seed = Math.floor(Math.random() * 2 ** 31);这个seed在每次调用line()时作为参数传入 Rough.js。结果是:同一个页面上多个wired-divider的抖动形态各不相同,如同每个人手写的线都不一样;而同一实例的多次重绘(如窗口缩放)则会复用同一个 seed,保持线条形态稳定一致。
响应式重绘机制
WiredDivider通过两种机制监听尺寸变化(src/wired-divider.ts#L52-L72):
- 优先使用
ResizeObserver观察宿主元素,尺寸变化时触发wiredRender(); - 若环境不支持
ResizeObserver,则回退到监听window的resize事件(passive: true)。
而wiredRender()内部还会做一次尺寸比对(src/wired-base.ts#L45-L58):只有宽高真正变化时才清空旧的 SVG 子节点并按新尺寸重绘,否则直接跳过,避免无意义的重复绘制开销。组件在disconnectedCallback中会正确解除监听,防止内存泄漏。
与整个组件库的关系
wired-divider只是 wired-elements 中 20 余个手绘组件之一,总入口 src/wired-elements.ts 会导出全部组件(包括WiredButton、WiredInput、WiredCard等),因此安装一个包即可按需引用任意组件。各组件共享 WiredBase 基类 的"尺寸变化重绘 + 随机种子 + currentColor 上色"这套统一机制,使用体验一致。更多组件的 API 文档位于 docs 目录,组件行为也遵循 README 中的通用安装与使用约定(见 README.md)。
许可证
wired-divider 随 wired-elements 整体以 MIT License 开源,版权归 Preet Shihn 所有(见 docs/wired-divider.md 与 package.json 中的 license 字段)。你可以在个人与商业项目中自由使用,包括 wireframe 工具、原型演示和产品 UI。
- UI组件
- 前端
【免费下载链接】wired-elements
Collection of custom elements that appear hand drawn. Great for wireframes or a fun look.
相关推荐
flask-restful-swagger源码解析:Swagger规范提取的实现原理
flask restful swagger源码解析:Swagger规范提取的实现原理 flask restful swagger是一个专为Flask RESTf
后端开发工具MJML 邮件开发指南:mj-divider 分隔线组件从配置到源码原理全解析
MJML 邮件开发指南:mj divider 分隔线组件从配置到源码原理全解析 导读 mj divider 是 MJML 标准组件库中用于在响应式邮件中插入水平
前端CLIwired-elements 之 wired-radio-group:手绘风格单选组组件完整使用与源码解析
wired elements 之 wired radio group:手绘风格单选组组件完整使用与源码解析 导读 wired radio group 是 wir
UI组件前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考