- UI组件
- 前端
【免费下载链接】wired-elements
Collection of custom elements that appear hand drawn. Great for wireframes or a fun look.
wired-listbox 是 wired-elements 系列中用于单选列表选择的手绘风 Web Component:选中的wired-item会被高亮,支持垂直(默认)与水平两种布局,并能通过键盘方向键快速切换选项。本文以 docs/wired-listbox.md 为主线,结合仓库源码与示例,完整讲解它的安装方式、HTML 用法、属性、自定义 CSS 变量、事件机制以及底层实现原理,帮助你直接把它应用到线框图(wireframe)、原型或任何需要"手绘感"界面的项目中。
什么是 wired-listbox
wired-listbox 是一个外观呈现手绘风格的列表选择控件。它本身不直接渲染选项,而是通过<slot>接收一组 wired-item 作为列表项;选中项的文本颜色与背景会被高亮,同时组件外围会用 RoughJS 画出一圈"手绘感"的矩形边框。它可以垂直排列(默认),也可以设置horizontal变为水平排列,适用于工具栏、菜单、选项分组等场景。
完整演示与 wired-elements 全部组件的展示可访问官方演示站(wiredjs.com)。本组件的完整参考文档位于 docs/wired-listbox.md,配套可运行示例见 examples/listbox.html。
安装与引入
在 JavaScript 项目中添加 wired-elements:
npm i wired-elements然后在模块代码中引入:
import { WiredListbox } from 'wired-elements'; // 或按需引入单个组件 import { WiredListbox } from 'wired-elements/lib/wired-listbox.js';也可以直接在 HTML 页面中通过 CDN 加载 ES Module(无需打包工具):
<script type="module" src="https://unpkg.com/wired-elements/lib/wired-listbox.js?module"></script>注意:由于 wired-listbox 依赖同系列组件
wired-item(选项项),若只通过上面的方式按需加载,需要一并引入 wired-item 模块。参见 examples/listbox.html,它同时加载了wired-item.js与wired-listbox.js;完整包入口 src/wired-elements.ts 中两者也都已统一导出。
基本用法
在 HTML 中使用wired-listbox,内部放置若干个带value的wired-item:
<wired-listbox id="combo" selected="two"> <wired-item value="one">Number One</wired-item> <wired-item value="two">Number Two</wired-item> <wired-item value="three">Number Three</wired-item> </wired-listbox>水平排列并自定义选中项颜色:
<wired-listbox horizontal selected="two" style="--wired-item-selected-color: darkred; --wired-item-selected-bg: pink;"> <wired-item value="one">Number One</wired-item> <wired-item value="two">Number Two</wired-item> <wired-item value="three">Number Three</wired-item> </wired-listbox>第一个示例渲染为垂直列表,selected="two"表示初始选中的是value="two"那一项;第二个示例加了horizontal属性,三个选项横向排布,并通过内联样式覆盖选中项的文字颜色为 darkred、背景为 pink。
在 examples/listbox.html 中还可以看到另一种定制方式:直接给wired-listbox或自定义 class 设置 CSS 变量,例如将选中背景统一设为darkblue,或通过.customListBox类为水平列表单独定制pink背景与darkred文字。
属性(Properties)
| 属性 | 类型 | 说明 |
|---|---|---|
horizontal | Boolean | 是否将选项水平排列,默认为false(垂直排列)。 |
selected | String | 当前选中项的 value 值。 |
value | Object | 选中项的{ value, text }对象,由组件内部维护,反映当前选中项的值与文本。 |
horizontal:源码中以@property({ type: Boolean }) horizontal = false声明(见 src/wired-listbox.ts)。它在updated()中通过给宿主元素添加/移除wired-horizontalclass 生效:默认::slotted(wired-item)为display: block纵向堆叠,加上wired-horizontal后变为display: inline-block横向排布(见 src/wired-listbox.ts)。selected:声明为字符串属性(src/wired-listbox.ts)。它既可以作为 HTML 属性在初始化时指定默认选中项,也可以在用户点击或键盘操作时被组件自动更新。value:对象类型({ value: string; text: string })。每次刷新选中状态时,组件会把当前选中项的value和textContent组装成对象存入该属性;没有匹配项时则为undefined(见 src/wired-listbox.ts)。这便于在框架中直接读取选中项的结构化数据。
与
wired-combo不同:combo 是下拉弹层交互,而 listbox 始终把全部选项暴露在页面上(可垂直或水平排列),两者的键盘导航与选中逻辑则基本一致。
自定义 CSS 变量
| 变量 | 作用 |
|---|---|
--wired-item-selected-bg | 选中项的"手绘"高亮背景颜色。 |
--wired-item-selected-color | 选中项的文字颜色。 |
这两个变量实际作用于wired-item的样式(见 src/wired-item.ts):
button.selected { color: var(--wired-item-selected-color, #fff); } svg path { stroke: var(--wired-item-selected-bg, #000); stroke-width: 2.75; fill: transparent; }也就是说,未设置变量时默认值为:选中文字白色(#fff)、高亮描边黑色(#000)。选中时wired-item内部会显示一个带hachureFill(手绘阴影线填充)的 SVG 覆盖层作为高亮背景,其描边颜色由--wired-item-selected-bg控制;同时文字颜色由--wired-item-selected-color控制。
由于 CSS 变量天然具备继承性,你可以在wired-listbox元素上、容器元素上或通过 class 声明这些变量,从而批量或按实例定制多个列表项的选中样式——这正是 examples/listbox.html 中两种定制方式的原理。
事件
selected:当用户点击某个wired-item选中它时触发,事件详情为{ selected: 选中的 value 字符串 }。
监听示例:
const listbox = document.getElementById('combo'); listbox.addEventListener('selected', (e) => { console.log('selected value:', e.detail.selected); });实现上,点击事件由onItemClick处理:它把event.target的value写入selected,刷新选中状态后调用fireSelected()派发事件(见 src/wired-listbox.ts)。事件通过CustomEvent派发,设置了composed: true与bubbles: true(见 src/wired-base.ts),因此即使组件内部使用 Shadow DOM,事件也能正常冒泡到外部,便于在普通 DOM 或框架中监听。
键盘导航与无障碍支持
wired-listbox 内置了完整的键盘操作与 ARIA 支持,这在 src/wired-listbox.ts 的firstUpdated()中初始化:
- 组件被赋予
role="listbox",每个wired-item被赋予role="option"(见 src/wired-listbox.ts)。 - 默认
tabIndex为 0(或读取已有的tabindex属性),保证可以通过 Tab 聚焦。 - 键盘事件处理:
←(37)/↑(38):selectPrevious(),选中上一个选项;当前在首项时回绕到末项。→(39)/↓(40):selectNext(),选中下一个选项;当前在末项时回绕到首项。- 聚焦时通过 CSS
:host(:focus) path { stroke-width: 1.5; }让手绘边框略微加粗,提供视觉焦点反馈。
- 选中项会被设置
aria-selected="true"并移除上一项的该属性(见 src/wired-listbox.ts),方便读屏软件等辅助技术识别当前选中项。
键盘选择同样会派发selected事件,因为selectPrevious/selectNext内部在更新selected后也会调用fireSelected()。
源码原理:从 slot 收集到边框绘制
1. 选项收集与选中刷新
组件渲染结构非常简单(src/wired-listbox.ts):
<slot id="slot" @slotchange="${() => this.requestUpdate()}"></slot> <div id="overlay"> <svg id="svg"></svg> </div>- 通过
slotchange触发重新渲染;updated()中使用assignedNodes()收集插槽内所有WIRED-ITEM元素,存入itemNodes并逐个设置role="option"(src/wired-listbox.ts)。这一收集只会执行一次(用!this.itemNodes.length判断),避免重复处理。 refreshSelection()遍历所有选项,按element.value === this.selected找到选中项,切换其selected布尔属性与aria-selected,并同步更新value对象(src/wired-listbox.ts)。
2. 手绘边框的绘制
wired-listbox 继承自WiredBase(见 src/wired-base.ts),基类负责测量尺寸、清空 SVG、调用子类draw()并在绘制完成后添加wired-renderedclass 让元素从透明过渡为可见。listbox 的draw()实现为:
protected draw(svg: SVGSVGElement, size: Point) { rectangle(svg, 0, 0, size[0], size[1], this.seed); }即调用 src/wired-lib.ts 中的rectangle(),借助 RoughJS 的roughRectangle配合随机种子seed生成"歪歪扭扭"的手绘矩形路径,作为整个列表的外框。每个组件实例在构造时都会生成随机seed(src/wired-base.ts),因此每次渲染的"笔迹"细节都略有不同,这正是手绘质感(sketchy look)的来源之一。
3. 选中高亮:wired-item 的手绘阴影填充
wired-item(src/wired-item.ts)内部渲染为一个<button>加一个隐藏的 SVG 覆盖层;当选中的布尔属性为true时:
- button 加上
selectedclass,文字颜色应用--wired-item-selected-color; - 覆盖层显示,其中通过
hachureFill()以手绘阴影线(hachure)填充整个按钮区域(src/wired-item.ts),描边颜色取自--wired-item-selected-bg。
因此,你看到的"选中高亮"本质是一层 RoughJS 生成的阴影线纹理,而不是普通的纯色背景——这也是与一般 UI 库选中态在视觉上最大的区别。
在框架中使用
wired-elements 是基于 Lit 构建的标准 Web Components,可以在任何框架中直接使用:
- 原生 HTML/JS:见上文基本用法,或直接运行 examples/listbox.html。
- React / Vue / Svelte:把
wired-listbox当作普通自定义元素即可;selected事件可通过各框架的事件绑定语法(如 React 的onSelected、Vue 的@selected)监听。
构建与本地查看
仓库使用 TypeScript 编译输出到lib/目录(见 tsconfig.json,outDir为./lib),构建命令为:
npm run build本地快速体验可在构建后,直接用浏览器打开 examples/listbox.html(该示例按../lib/wired-item.js与../lib/wired-listbox.js的路径引用编译产物)。
总结
wired-listbox是 wired-elements 系列中专注单选列表的组件,垂直/水平两种布局分别覆盖菜单列表与横向选项栏两类场景。- 核心 API 只有三个:
horizontal(布局)、selected(当前选中值)、value(结构化选中对象),配合selected事件即可完成绝大部分交互闭环。 - 视觉定制通过
--wired-item-selected-bg与--wired-item-selected-color两个 CSS 变量实现,配合示例中的 class 写法可以做到按实例精确控制。 - 从源码看,选中高亮是 RoughJS 阴影线填充,外框是随机种子驱动的手绘矩形;键盘方向键、
role="listbox"/role="option"/aria-selected则保证了与原生列表相近的可访问性。
许可证:MIT License,作者 Preet Shihn。更多组件用法可继续查阅 docs 目录下的其他组件文档。
- UI组件
- 前端
【免费下载链接】wired-elements
Collection of custom elements that appear hand drawn. Great for wireframes or a fun look.
相关推荐
Wired-Elements项目中的手绘风格列表组件wired-listbox详解
Wired Elements项目中的手绘风格列表组件wired listbox详解 组件概述 wired listbox是Wired Elements项目提供的
UI组件前端wired-listbox组件应用:创建手绘风格下拉列表
wired listbox组件应用:创建手绘风格下拉列表 在现代网页设计中,传统下拉列表往往显得单调乏味,难以吸引用户注意力。wired listbox组件作为
UI组件前端终极wired-elements开发指南:20个手绘风格组件属性与事件详解
终极wired elements开发指南:20个手绘风格组件属性与事件详解 wired elements是一套独特的手绘风格Web组件库,通过简单的HTML标签
UI组件前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考