- UI组件
- 前端
【免费下载链接】wired-elements
Collection of custom elements that appear hand drawn. Great for wireframes or a fun look.
WiredSlider 是 wired-elements 手绘风格 Web Components 组件库中用于"从一段数值范围内选择取值"的滑块组件,它以粗糙手绘线条代替浏览器原生滑块外观,非常适合线框图、原型演示或希望界面更有趣味的场景。本文以 docs/wired-slider.md 为主线,结合仓库源码 src/wired-slider.ts 与其示例页面 examples/slider.html,完整讲解安装引入、属性与 CSS 变量配置、change 事件用法,并深入到组件"原生 input 驱动交互 + SVG 覆盖层渲染手绘视觉"的实现原理,读完即可在项目中直接落地使用并看懂其运行机制。
一、组件概览:一个"看起来是手绘的"原生滑块
<wired-slider>是一个基于 Lit 构建的自定义元素,用户通过拖动滑块拇指(knob)在 min 与 max 定义的数值区间内选择取值。默认范围是 0–100。它的核心设计思路是:交互完全交给隐藏在底层的原生<input type="range">(保证键盘、鼠标、触屏与无障碍访问的行为一致性),而在其上方叠加一层手工绘制的 SVG 覆盖层,把轨道和滑块拇指重绘成手绘草图风格,从而在保留原生控件可用性的同时获得完全自定义的视觉表现。
从源码看,该组件继承了组件库统一的WiredBase基类(src/wired-base.ts),并导出为wired-slider自定义元素(src/wired-slider.ts);同时通过 src/wired-elements.ts 作为组件库整体入口对外发布。
二、安装与引入
在 JavaScript 项目中安装 wired-elements:
npm i wired-elements然后在代码中按需导入:
import { WiredSlider } from 'wired-elements'; // 或单独导入该组件 import { WiredSlider } from 'wired-elements/lib/wired-slider.js';也可以在 HTML 页面中直接通过模块脚本加载(?module表示按 ES Module 方式加载):
<script type="module" src="https://unpkg.com/wired-elements/lib/wired-slider.js?module"></script>补充说明(基于仓库事实):仓库的 package.json 声明主入口为lib/wired-elements.js(main与module字段均指向该文件),类型声明为lib/wired-elements.d.ts;lib目录由npm run build(执行tsc,见 tsconfig.json,输出目录outDir: "./lib")从 src 目录编译生成,因此wired-elements/lib/wired-slider.js即组件编译后的产物路径。
三、基本用法
在 HTML 中使用组件,最小实例只需一个空标签:
<wired-slider></wired-slider> <wired-slider disabled></wired-slider> <wired-slider value="10" min="5" max="15"></wired-slider>- 第一个:使用默认范围 0–100;
- 第二个:禁用状态,不可交互;
- 第三个:将取值限定在 5–15 之间,并初始化为 10。
仓库自带的示例页面 examples/slider.html 展示了更多组合,包括通过内联样式调整宽度、禁用状态以及自定义颜色变量:
<wired-slider value="40" style="width: 600px;"></wired-slider> <wired-slider value="60" disabled></wired-slider>需要注意,组件的宿主(:host)默认宽度为 300px(见 src/wired-slider.ts),SVG 绘制区域会随实际渲染尺寸自适应(canvasSize()通过getBoundingClientRect()获取真实宽高,src/wired-slider.ts),因此用 CSS 调整宽度即可得到不同长度的滑块。
四、属性(Properties)详解
官方文档明确了value、min、max三个核心属性;结合源码(src/wired-slider.ts),组件实际还额外支持step与disabled,完整的属性清单如下:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
value | Number | 无(初始为min) | 滑块的当前数值。注意它是一个 getter/setter 属性,读写会直接同步到底层<input type="range">的值(src/wired-slider.ts) |
min | Number | 0 | 滑块可选取的最小值 |
max | Number | 100 | 滑块可选取的最大值 |
step | Number | 1 | 每次拖动的最小步进值,会同步写入底层 input 的step属性 |
disabled | Boolean | false | 禁用组件。使用reflect: true反射为 HTML 属性,禁用时宿主透明度降为 0.45、pointer-events: none,不可交互(src/wired-slider.ts) |
几个源码层面的细节值得注意:
value的读取与设置:读取时直接返回底层 input 的数值(+this.input.value);设置时同步写入 input,并立即调用updateThumbPosition()刷新手绘拇指的位置。若在元素首次渲染完成前设置value(此时 input 尚不存在),值会被暂存在pendingValue,待firstUpdated生命周期中统一应用(src/wired-slider.ts)。- 属性的类型转换:
min、max、step声明为Number类型属性,Lit 会自动完成字符串属性到数值的转换。 - 手绘拇指的定位计算:
updateThumbPosition()中按pct = (value - min) / Math.max(step, max - min)计算百分比,再将拇指沿 X 轴平移pct * (canvasWidth - 24)像素(24 为拇指的宽高),从而让手绘拇指始终与底层 input 的滑块位置一致(src/wired-slider.ts)。
五、自定义 CSS 变量(Custom CSS Variables)
官方文档给出了三个可自定义颜色的 CSS 变量,用于在不侵入组件内部样式的条件下换肤:
| CSS 变量 | 说明 |
|---|---|
--wired-slider-knob-zero-color | 当值处于最小值(value === min)时滑块拇指(knob)的颜色 |
--wired-slider-knob-color | 当值不在最小值时滑块拇指的颜色 |
--wired-slider-bar-color | 滑块轨道(bar)的颜色 |
结合源码可以确认实际生效的变量与默认值(src/wired-slider.ts):
- 拇指默认色
--wired-slider-knob-color,默认回退值rgb(51, 103, 214)(蓝色),同时作用于拇指的fill与stroke; - 轨道默认色
--wired-slider-bar-color,默认回退值rgb(0, 0, 0)(黑色),stroke-width: 1; - 额外还有一个文档未强调的
--wired-slider-knob-outline-color:当滑块获得焦点(input:focus触发)时,拇指描边切换为该变量,默认#000,同时fill-opacity降为 0.8,用于给出清晰的可聚焦视觉反馈。
提示:文档中列出的
--wired-slider-knob-zero-color在当前仓库版本的源码样式中未出现实际引用(当前实现仅使用--wired-slider-knob-color),编写样式时建议以源码中真正生效的--wired-slider-knob-color、--wired-slider-bar-color、--wired-slider-knob-outline-color为准,以保证视觉效果可预期。
使用示例(与示例页面 examples/slider.html 中的.custom类一致):
<style> .custom { width: 200px; --wired-slider-knob-color: green; --wired-slider-bar-color: blue; } </style> <wired-slider class="custom" value="25"></wired-slider>六、事件(Events)
组件对外暴露一个change事件,在用户改变滑块取值时触发。
- 触发时机:底层 input 派发
input事件时(拖动过程中持续触发),组件内部处理器onInput会先stopPropagation()阻止原生事件冒泡,再调用updateThumbPosition()同步拇指位置,最后派发自定义change事件(src/wired-slider.ts)。 - 事件细节:通过基类的
fire()方法派发,fireEvent使用CustomEvent并设置bubbles: true与composed: true,事件可以穿透 Shadow DOM 冒泡到外层文档;携带的detail结构为{ value: number },其中value是当前 input 的数值(src/wired-base.ts)。
监听示例:
const slider = document.querySelector('wired-slider'); slider.addEventListener('change', (e) => { console.log('当前值:', e.detail.value); });七、源码实现原理:原生 input + SVG 手绘覆盖层
1. 双层 DOM 结构
render()产出的模板(src/wired-slider.ts)包含两层:
- 一个全宽的原生
<input type="range">,携带min、max、step、disabled绑定,负责全部交互与键盘操作;其样式被设置为透明背景、无边框、自定义 thumb 为 24×24 的透明圆点(兼容 WebKit 与 Firefox,见 src/wired-slider.ts),视觉上不可见; - 一个绝对定位的
#overlay容器,内含<svg>,用于承载手绘轨道与拇指。
2. 手绘图形如何生成
组件的draw()方法(src/wired-slider.ts)调用组件库的绘图工具 src/wired-lib.ts:
line(svg, 0, midY, size[0], midY, this.seed)绘制一条贯穿组件宽度的水平轨道,midY取高度一半(Math.round(size[1] / 2)),并加上bar类以便应用轨道颜色;ellipse(svg, 12, midY, 24, 24, this.seed)在轨道左端绘制一个 24×24 的椭圆作为滑块拇指,加上knob类。
这两个函数内部调用 roughjs 的渲染器生成"粗糙"的 SVG 路径:随机偏移(maxRandomnessOffset: 2)、粗糙度(roughness: 1)、弯曲度(bowing: 0.85)等参数在 src/wired-lib.ts 中统一配置,每个组件实例使用独立的随机种子(seed = Math.floor(Math.random() * 2 ** 31),见 src/wired-base.ts),因此每个滑块的笔迹都略有不同,呈现出自然手绘的不规则感。
3. 绘制生命周期与尺寸自适应
基类wiredRender()(src/wired-base.ts)负责在每次更新后清空 SVG、按真实渲染尺寸设置 SVG 宽高并调用draw();当尺寸未变化时会跳过重绘以节省开销。wiredRender()结束后元素被加上wired-rendered类,宿主透明度从 0(默认隐藏,见 src/wired-base.ts)过渡到 1,避免闪烁。
4. 焦点与键盘可达性
组件覆写了focus()方法,将焦点直接委托给底层 input(src/wired-slider.ts),保证slider.focus()与 Tab 键导航都能正常工作,并且焦点态通过input:focus + div svg .knob选择器在视觉上高亮手绘拇指。
八、可运行的完整示例
综合以上内容,给出一个开箱即用的完整页面(可对照仓库示例 examples/slider.html):
<!DOCTYPE html> <html> <head> <script type="module" src="../lib/wired-slider.js"></script> <style> wired-slider { margin: 16px 0; max-width: 100%; } .theme-a { width: 320px; --wired-slider-knob-color: #e91e63; --wired-slider-bar-color: #3f51b5; } </style> </head> <body> <wired-slider value="40"></wired-slider> <wired-slider id="range" value="10" min="5" max="15" step="1"></wired-slider> <p id="out">当前值:10</p> <wired-slider value="60" disabled></wired-slider> <wired-slider class="theme-a" value="25"></wired-slider> <script> const slider = document.getElementById('range'); slider.addEventListener('change', (e) => { document.getElementById('out').textContent = '当前值:' + e.detail.value; }); </script> </body> </html>页面中的第一个滑块演示默认范围 0–100;第二个演示带change事件监听与数值回显;第三个演示禁用态;第四个演示通过 CSS 变量定制拇指与轨道颜色。
九、组合使用与许可
<wired-slider>通过 src/wired-elements.ts 与组件库中的按钮、卡片、输入框等一起导出,可与它们自由组合构建完整的手绘风格表单或原型页面;单个组件的独立引入路径wired-elements/lib/wired-slider.js也保证了按需加载的灵活性。
本项目基于 MIT 协议开源(见仓库根目录 LICENSE),作者为 Preet Shihn。在原型设计、线框工具、教学演示或任何希望弱化"机械感"的交互界面中,WiredSlider 都能以极低的接入成本提供原生化交互与独特的手绘视觉体验。
- UI组件
- 前端
【免费下载链接】wired-elements
Collection of custom elements that appear hand drawn. Great for wireframes or a fun look.
相关推荐
wired-elements 手绘风日历组件 wired-calendar 实战指南:属性、事件与源码实现解析
wired elements 手绘风日历组件 wired calendar 实战指南:属性、事件与源码实现解析 wired calendar 是 wired e
UI组件前端wired-radio 手绘单选按钮组件实战指南:wired-elements 安装、属性、样式定制与源码实现
wired radio 手绘单选按钮组件实战指南:wired elements 安装、属性、样式定制与源码实现 wired radio 是 wired elem
UI组件前端终极wired-elements开发指南:20个手绘风格组件属性与事件详解
终极wired elements开发指南:20个手绘风格组件属性与事件详解 wired elements是一套独特的手绘风格Web组件库,通过简单的HTML标签
UI组件前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考