- UI组件
- 前端
【免费下载链接】wired-elements
Collection of custom elements that appear hand drawn. Great for wireframes or a fun look.
本篇技术指南以 wired-elements 仓库中的<wired-button>组件为核心,系统讲解这一手绘风格(hand-drawn / sketchy)Web Component 的安装方式、HTML 用法、属性与事件,并结合 wired-button.ts 与 wired-base.ts 等源码,剖析其"草稿线稿"视觉效果的底层实现原理,包括 elevation 立体高度的绘制算法、随机抖动种子、响应式重绘机制与样式定制方法。读完本文,你将能独立在任意前端项目中接入并使用<wired-button>,并能依据源码证据按需调整其外观与行为。
一、wired-button 是什么
wired-button是 wired-elements 组件库中最基础的 UI 元素之一,一个外观呈"手绘草图"风格的按钮 Web Component。它适合用于线框图(wireframes)、产品原型(mockups),或任何希望呈现轻松、手绘观感的页面。
从实现上看,它基于 Lit 的dependencies中分别以lit: ^2.0.0-rc.1与roughjs: ^4.3.1声明。组件定义位于 wired-button.ts,通过@customElement('wired-button')注册,并统一从 wired-elements.ts 导出。
二、安装与引入
根据 docs/wired-button.md 的官方说明,有三种典型接入方式:
1. npm 安装
npm i wired-elements安装后,既可以从包入口导入,也可以只导入按钮这一个模块:
import { WiredButton } from 'wired-elements'; // 或 import { WiredButton } from 'wired-elements/lib/wired-button.js';从仓库 package.json 可见,包的module与main均指向lib/wired-elements.js,而 wired-elements.ts 通过export * from './wired-button'等语句汇总导出全部组件,因此两种导入方式都可用。
2. 通过 CDN 直接加载(无需构建工具)
<script type="module" src="https://unpkg.com/wired-elements/lib/wired-button.js?module"></script>3. 本地源码构建
当前仓库为 TypeScript 源码形态,构建命令定义在 package.json 的scripts中(build: rm -rf lib && tsc),使用 TypeScript 编译到lib/目录。仓库内 examples/button.html 即采用本地产物加载:
<script type="module" src="../lib/wired-button.js"></script>如需拉取源码本地尝试,可克隆本镜像仓库:
git clone https://gitcode.com/gh_mirrors/wi/wired-elements cd wired-elements npm install npm run build随后用本地 HTTP 服务(如npx serve)打开 examples/button.html 即可预览效果。
三、HTML 基本用法
导入模块后,即可在 HTML 中像使用原生元素一样书写:
<wired-button>Click Me</wired-button> <wired-button disabled>Disabled</wired-button> <wired-button elevation="3">Elevation</wired-button>- 按钮文字直接放在标签内部,由
<slot>承载; disabled为布尔属性,存在即生效;elevation为数字属性,控制按钮的"立体厚度"。
仓库自带的 examples/button.html 演示了更丰富的组合,包括普通按钮、elevation="5"的高厚度按钮、disabled禁用按钮,以及带onclick和内联样式(id="styled",黄色背景红色文字)的按钮:
<wired-button id="btn1">Submit</wired-button> <wired-button elevation="5">Hello, world!</wired-button> <wired-button disabled>Submit</wired-button> <wired-button id="styled" onclick="alert('ddd');">Click me</wired-button>四、属性详解与源码级解析
<wired-button>的公开属性只有两个,定义在 wired-button.ts:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
elevation | Number | 1 | 1~5(含)之间的整数,决定按钮"手绘厚度",值越大侧边线层数越多 |
disabled | Boolean | false | 禁用按钮,阻止交互并呈现禁用态样式 |
4.1 elevation:手绘厚度的实现
elevation在源码中并非直接使用,而是先被"钳制"到 1~5 的有效区间。这一逻辑在 canvasSize 与 draw 中重复出现:
const elev = Math.min(Math.max(1, this.elevation), 5);也就是说,即使传入elevation="10",实际生效值也会被截断为 5,文档所述"Number between 1 and 5 (inclusive)"由源码强制保证。
绘制逻辑可以拆成两层理解:
- 轮廓层:通过
rectangle(svg, 0, 0, s.width, s.height, this.seed)绘制一个手绘矩形作为按钮主体(见 wired-button.ts)。 - 厚度层:
for (let i = 1; i < elev; i++)循环中,每增加一层,就在按钮右缘和下缘各追加两条手绘边线,偏移量随层数递增(i * 2),同时线条透明度随层数递减——第 1 层为(75 - 10) / 100 = 0.65,越靠外的层越淡,形成类似纸张堆叠的立体透视效果(见 wired-button.ts)。
同时,画布尺寸也会随 elevation 增大:canvasSize()返回的宽高为按钮尺寸 + (elev - 1) * 2,为侧边线预留空间。这就是elevation从视觉和布局两个维度共同作用的原因。
4.2 disabled:禁用态的三重保障
disabled属性带有reflect: true修饰(wired-button.ts),因此会同步反映为元素上的 HTML 属性,便于 CSS 选择器匹配。其禁用效果由三部分协同完成:
- 渲染层:内部
<button>绑定?disabled="${this.disabled}",原生按钮语义被禁用(wired-button.ts); - 样式层:
button[disabled]规则设置opacity: 0.6、浅灰背景rgba(0, 0, 0, 0.07)、cursor: default以及pointer-events: none,从视觉与命中测试两方面屏蔽交互(wired-button.ts); - 焦点层:由于
pointer-events: none,鼠标无法再触发点击;键盘焦点行为则由组件覆写的focus()方法委托给内部按钮(wired-button.ts)。
五、事件与交互
按 docs/wired-button.md 的说明,组件公开的事件为:
click—— 按钮被点击(或作为表单按钮被"提交")时触发。
从实现看,<wired-button>内部渲染的是一个未显式指定type的原生<button>(wired-button.ts),根据 HTML 规范默认type="submit",因此当它位于<form>内且未禁用时,点击会触发表单提交行为——这正是文档中 "clicked/submitted" 的由来。组件未额外自定义事件,所有交互都收敛到标准click事件上,可直接使用onclick、addEventListener等常规方式监听。
交互细节上,源码为内部按钮追加了按压缩放与焦点高亮反馈:
button:active path:按下时手绘路径scale(0.97)并微移,产生"被按下去"的反馈(wired-button.ts);button:focus path:聚焦时描边加粗至stroke-width: 1.5,保证键盘可达性可见(wired-button.ts);button::-moz-focus-inner { border: 0 }:去除 Firefox 下按钮默认的虚线焦点框,避免与手绘风格冲突(wired-button.ts)。
六、样式定制
wired-button的样式全部基于内部<button>与 SVG<path>实现,因此可通过 CSS 变量继承与常规 CSS 规则定制,无需修改组件源码:
- 颜色继承:基类 wired-base.ts 的
BaseCSS定义path { stroke: currentColor; stroke-width: 0.7; fill: transparent; },即所有手绘线条使用宿主元素的color作为描边色。因此直接给<wired-button>设置color即可整体换色。示例 examples/button.html 中通过id="styled"搭配color: red; background: yellow;呈现了红字黄底的组合按钮。 - 字体与排版:组件内置
font-size: 14px、letter-spacing: 1.25px、text-transform: uppercase、padding: 10px等规则(wired-button.ts)。如需覆盖,可在自定义样式中以更高优先级规则改写;font-family继承自父级(font-family: inherit),便于与页面字体统一。 - 背景与边框:内部按钮为
border: none; background: none,若想给按钮主体加底色,可直接设置背景色(如上例的黄色),手绘轮廓绘制在覆盖层#overlay的 SVG 中(wired-button.ts),不会遮挡内容。
注意:基类BaseCSS中:host { opacity: 0 }、:host(.wired-rendered) { opacity: 1 }意味着组件在 SVG 手绘路径渲染完成前保持透明,渲染完成后由 wiredRender 添加wired-rendered类使元素显现,避免"先看到普通文本、后出现线稿"的闪烁。
七、实现原理:手绘效果从哪来
<wired-button>只是WiredBase抽象基类的一个实现,手绘能力的核心链路如下:
- 基类渲染调度:
WiredBase(wired-base.ts)在updated()时调用wiredRender(),后者先通过canvasSize()获取画布尺寸,与上次尺寸比较(尺寸未变且非强制时跳过重绘),随后清空 SVG、设置宽高并调用子类实现的draw(svg, size)绘制,最后把lastSize记录下来并加上wired-rendered类。 - 随机种子:每个组件实例在基类中初始化一个随机种子
seed = Math.floor(Math.random() * 2 ** 31)(wired-base.ts),并把它传给所有 RoughJS 绘图函数。同一实例在不同重绘间保持相同抖动形状,而不同实例形状各不相同——这是"每一颗手绘按钮都长得不一样"的来源。 - 手绘几何:
wired-button的draw()调用 wired-lib.ts 中的rectangle()与line()工具函数,这些函数将 RoughJS 渲染器产出的操作序列(move / bcurveTo / lineTo)转换成 SVG<path>的d属性。RoughJS 通过maxRandomnessOffset、roughness、bowing等参数(见 wired-lib.ts 的options())在直线与贝塞尔曲线上叠加微小的随机偏移,从而形成"铅笔草稿"般的抖动线条。 - 自适应重绘:组件在构造时创建
ResizeObserver监听内部按钮尺寸变化,尺寸改变时强制重绘(wired-button.ts),并在disconnectedCallback中解除监听(wired-button.ts),确保按钮内容变化或容器缩放时线稿始终贴合实际尺寸。
八、在框架中使用
由于<wired-button>是标准 Web Component,在 React、Vue、Svelte 等框架中同样可以直接在模板里使用该标签,并按框架惯例绑定事件(如 React 的onClick)。仓库 README.md 提供了对应框架的在线演示入口,examples/button.html 则是零框架环境下最直接的参考样板——一个纯 HTML 文件即可跑通全部属性组合。
总结
<wired-button>是 wired-elements 中结构最精简、却最能体现"手绘风"核心思想的组件:仅两个属性(elevation、disabled)与一个标准事件(click),背后却由 Lit 的响应式渲染、RoughJS 的随机抖动几何、WiredBase的重绘调度与ResizeObserver的自适应机制共同支撑。理解它的实现链路,就等于掌握了整个 wired-elements 组件库的通用手绘渲染范式,对后续学习<wired-card>、<wired-input>等兄弟组件(见 docs/ 目录对应文档)大有裨益。
本项目采用 MIT License。
- UI组件
- 前端
【免费下载链接】wired-elements
Collection of custom elements that appear hand drawn. Great for wireframes or a fun look.
相关推荐
GitHub_Trending/ma/machine-learning-for-trading中的无监督学习:PCA与聚类分析
GitHub_Trending/ma/machine learning for trading中的无监督学习:PCA与聚类分析 在量化交易领域,无监督学习技术能
示例工程金融科技机器学习人工智能深度学习Wired Elements 手绘风格进度环组件 wired-progress-ring 详解
Wired Elements 手绘风格进度环组件 wired progress ring 详解 组件概述 Wired Elements 项目中的 wired p
UI组件前端Wired-Elements项目中的手绘风格列表组件wired-listbox详解
Wired Elements项目中的手绘风格列表组件wired listbox详解 组件概述 wired listbox是Wired Elements项目提供的
UI组件前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考