news 2026/9/23 11:57:52

wired-listbox 手绘风列表选择组件:属性、事件与源码原理完全指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
wired-listbox 手绘风列表选择组件:属性、事件与源码原理完全指南
  • UI组件
  • 前端

【免费下载链接】wired-elements

Collection of custom elements that appear hand drawn. Great for wireframes or a fun look.

项目地址:https://gitcode.com/gh_mirrors/wi/wired-elements
点击查看免费下载

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.jswired-listbox.js;完整包入口 src/wired-elements.ts 中两者也都已统一导出。

基本用法

在 HTML 中使用wired-listbox,内部放置若干个带valuewired-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)

属性类型说明
horizontalBoolean是否将选项水平排列,默认为false(垂直排列)。
selectedString当前选中项的 value 值。
valueObject选中项的{ 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 })。每次刷新选中状态时,组件会把当前选中项的valuetextContent组装成对象存入该属性;没有匹配项时则为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.targetvalue写入selected,刷新选中状态后调用fireSelected()派发事件(见 src/wired-listbox.ts)。事件通过CustomEvent派发,设置了composed: truebubbles: 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.

项目地址:https://gitcode.com/gh_mirrors/wi/wired-elements
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 11:55:10

有声书演播训练指南:从素材本地化到录音回听的完整闭环

简介&#xff1a;《喜马拉雅大学》精选演播练习素材是一份面向配音、朗读及有声书演播爱好者的PDF学习资源&#xff0c;旨在帮助不同基础的声音创作者在历史、悬疑、恐怖、奇幻、经管、都市、言情和儿童故事等类别中系统训练语气控制、节奏把握与角色塑造能力。资料共1个PDF文件…

作者头像 李华
网站建设 2026/9/23 11:48:07

动力电池PACK量产痛点解析:激光焊接隐性缺陷漏检如何规避?

在动力电池PACK智能制造产线中&#xff0c;激光焊接是决定电池包结构强度、密封性能与电气安全的核心工艺。随着GB38031新国标落地&#xff0c;动力电池安全质控门槛大幅提升&#xff0c;传统人工目检、金相抽检的滞后式质检模式&#xff0c;已经无法适配规模化量产需求。 动力…

作者头像 李华
网站建设 2026/9/23 11:47:46

从T40EVB原理图到硬件设计:电源树、DDR4与MIPI全解析

简介&#xff1a;北京君正T40EVB原理图PDF&#xff0c;面向从事AIoT、机器视觉硬件开发的嵌入式工程师与方案设计人员。T40是面向AIoT的通用SoC&#xff0c;采用XBurst2双核架构并集成RISC-V协处理器&#xff0c;内置8TOPS算力的AI引擎&#xff0c;支持4K ISP和多摄像头同时输入…

作者头像 李华
网站建设 2026/9/23 11:32:19

Atlas 300V 24G部署YOLO全攻略:从推理加速卡选型到性能调优

最近后台好几个朋友都在问同一个问题&#xff1a;Atlas 300V 24G到底算不算运算加速卡&#xff0c;还有人在网上搜“atlas部署yolo”却被一堆软文绕得云里雾里。说实话&#xff0c;这个问题我太有发言权了&#xff0c;去年开始我把公司几条视频结构化业务从GPU迁移到昇腾推理卡…

作者头像 李华