PVQ-UI 设计令牌与组件清单(模块文档 / 组件 API 说明)
状态:组件 API 人类可读说明(库 1.4.0) 机器可读唯一真源:
site/inc/components.json(官网画廊数据驱动,新增组件只改 JSON,画廊自动出现)。本文件引用 JSON,不再手抄示例。 用途:人类查阅组件 API / 设计令牌;判断"某组件是否已存在"以components.json为准。 关联:《PVQ-UI项目规则.md》(铁律,§2.3 定义 JSON 为唯一真源)、《PVQ-UI组件库开发方案.md》§3.5(架构)、《组件提取对照表.md》(旧→新映射)、《PVQ-UI组件库调用手册.md》(插件实操)
0. 文档地位
- 本文件是
pvq-ui组件 API 的人类可读说明;机器可读的唯一真源是site/inc/components.json(含组件 id / 名称 / 层 / 稳定性 / 附加说明note/ 示例 HTML,官网画廊遍历它渲染;stability严格二值stable/experimental)。 - 任何"这个组件库有没有 / 叫什么类"的问题,以
components.json为准;它里面没有的,才进入"新增组件"流程(先文档 → 再代码,见《PVQ-UI项目规则》§1)。本文件的示例仅作阅读参考,真值随 JSON 同步。 - 稳定性标记:
stable(承诺不破坏改)/experimental(接口可能调整,引用建议锁版本)。首版基线全部stable。
1. 当前库版本
1.4.0(当前库版本,2026-09-19 发布;升版本 + 部署全新目录pvq-ui/v1.4.0/,细节见 CHANGELOG 1.4.0 块):设计令牌化收口 + 真源规范化(零视觉变化,一处例外)。① base/admin 层硬编码色值令牌化:新增--pvq-border-hover/--pvq-border-hover-strong/--pvq-surface-active/--pvq-primary-alt/--pvq-danger-hover/--pvq-warning-strong/--pvq-warning-gradient(-hover)/--pvq-warning-shadow等令牌,语义色深浅派生统一改color-mix()(与等价 rgba 逐位相同),全库规则体内已无非豁免字面量;② 补齐被引用却缺失的令牌:--pvq-surface-alt(有一处无兜底、背景静默失效)、--pvq-radius-md、--pvq-text-strong、--pvq-toast-offset-x/-y;其中--pvq-text-strong由蓝调兜底改为与--pvq-text同值(唯一可见变化:Checkbox/Radio/Bookmark/DataGrid 的 hover 强调文字由蓝转绿);③components.json的stability二值化(严格stable/experimental)+ 新增note字段承载来源/版本,画廊标签改为「层 · 稳定性(note)」拼接渲染;④ 命名受控例外登记(pvq-cb-variant-*/pvq-rb-variant-*);⑤ 仓库一致性修正(版本七处、组件真源判据、部署 URL 子目录、移除 latest 承诺、官网文档白名单与快速开始示例)。令牌清单见 §2.8,调用方需把PVQ_UI_Loader::enqueue()与 loaderDEFAULT_VERSION升至'1.4.0'。1.3.1(2026-09-19 发布;升版本 + 部署全新目录pvq-ui/v1.3.1/,细节见 CHANGELOG 1.3.1 块):锚点浮层 Popover(§3.1 Base 层新增,experimental,回流自 pvq-weixinyuedu):以元素为锚、脱离文档流、按需显隐的浮层(术语解释 / 作者卡 / 预览 / 迷你详情)。类.pvq-popover+__body/__foot/__arrow,修饰符--open(打开态,JS 加)/--above(JS 判定的上方位置);开关只有两态——hidden属性(彻底不显示)+--open(淡入)。定位用position:fixed+getBoundingClientRect()实时算并写内联top/left,不依赖任何祖先position;视口边缘自动翻转 + 双向夹取;JS 双入口PVQUI.popover(anchor, opts)与声明式[data-pvq-popover="<浮层 id>"](initPopovers()随initAll自动接管、幂等);事件pvq-popover:open/pvq-popover:close(reason ∈pointer/focus/click/escape/outside/api)。落库决策与完整契约见《PVQ-UI回流落库-Popover锚点浮层.md》,用法见调用手册 §4.7。调用方需把PVQ_UI_Loader::enqueue()与 loaderDEFAULT_VERSION升至'1.3.1';版本七处(两个 loader 的DEFAULT_VERSION、assets/css/pvq-ui.css与assets/js/pvq-ui.js的@version、site/inc/config.php的PVQ_UI_VERSION、site/inc/components.json的version、readme.md当前版本与示例)已同步,另加CHANGELOG.md版本块与本文件。1.3.0(2026-09-19 发布;升版本 + 部署全新目录pvq-ui/v1.3.0/,细节见 CHANGELOG 1.3.0 块):① 浮层通知 Toast(§3.1 Base 层新增,experimental,回流自 pvq-weixinyuedu):双入口PVQUI.toast(options)与[data-pvq-toast],四语义success/info/warning/error,同屏至多 4 条、超出挤走最旧,悬停暂停计时,事件pvq-toast:open/pvq-toast:close;② 横幅可关闭(§3.1 Banner 增强):待办 / 提醒类横幅末尾加.pvq-banner__close[data-pvq-banner-close],initBanners()自动接管并派发pvq-banner:close,不含关闭按钮的横幅行为不变;③ 二次确认弹窗幂等修复:initConfirms()的document级委托补confirmsBound守卫(此前随initAll在resize上重跑会逐次叠加等价监听),兑现本条与调用手册承诺的「幂等」。调用方需把PVQ_UI_Loader::enqueue()与 loaderDEFAULT_VERSION升至'1.3.0';版本七处(两个 loader 的DEFAULT_VERSION、assets/css/pvq-ui.css与assets/js/pvq-ui.js的@version、site/inc/config.php的PVQ_UI_VERSION、site/inc/components.json的version、readme.md当前版本与示例)已同步。1.2.11(2026-09-05 固化升版,无功能改动,细节见 CHANGELOG 1.2.10/1.2.11 块)。1.2.10 批次(因 CDN immutable 长缓存,1.2.10 覆盖部署未对端侧生效,随 1.2.11 全新目录才对外可见):Range 数值框可编辑 + 拖滑块修复(§3.1 Range,v1.2.10)、二次确认弹窗 Confirm Modal(§3.1 表单区,v1.2.10)、Select 玻璃磨砂下拉--glass(§3.1 Select,v1.2.10)、权重输入框 Weight(§3.4,v1.2.10,随 1.2.11 固化发布)。1.2.9。在 1.2.7(Field/Input 校验状态、附加变体、密码显隐切换、Collapse 修复)基础上:① Field/Input 输入框图标缩进适配 FA 7.2.0:--has-icon/--has-toggle的padding令牌化推导为calc(offset + size*1.25 + gap) ≈ 42px,修复 FA 7.2.0 图标盒宽导致的压字;② Field/Input 成功文案槽.pvq-field__success:与.pvq-field__error完全对称(绿字var(--pvq-success)+fa-circle-check+ flex 对齐),成功态文案不再借.pvq-field__help+ 内联color:var(--pvq-success)(避免违反令牌化纪律、且与帮助文案语义超载、无法共存)。同版保留 1.2.7 的.pvq-field--error(红框+红字+红辉光)/.pvq-field--success(绿框+绿辉光)/.pvq-field__label--required/pvq-field__error等;详见 §3.1。1.2.6 之前:1.2.5(Input/ColorField/Button 选择器特异性加固)删除按钮二次确认、1.1.x 演进。旧插件名仅在《组件提取对照表.md》§6 作为迁移映射出现。- ③ 搜索组件 Search(base 层,1.2.8 新增):独立
.pvq-search,形状归库、颜色归令牌--pvq-search-accent(默认--pvq-primary绿);功能变体--with-btn/--with-filter(复用库.pvq-select)/--loading/--sm,形状变体--pill/--underline/--ghost/--glass;库 JSinitSearches()派发pvq-search事件供插件接检索。详见 §3.1 Search 条目。 - ④ 前端迁移组件(1.2.9 并入):把 wolai 前端组件收为库默认,含 进度条 Progress(
.pvq-progress+--lg/--danger)、书签 Bookmark(.pvq-bookmark+__image/__url/__title/__description)、卡片化表格 Table(.pvq-table单元格独立圆角卡片、表头绿底、--striped斑马纹、__col--right/center列对齐、caption)、数据表格 DataGrid(.pvq-datagrid含工具栏搜索/排序三态/筛选双下拉/重置 + 入场动画,搜索/筛选为自包含可展开胶囊、点击空白收起)。颜色全部走--pvq-*令牌(森林绿),零硬编码。JSinitTables()(入场动画,[data-pvq-table]触发)与initDataGrids()(搜索/排序/筛选/重置,[data-pvq-datagrid]触发)随initAll自动调用、幂等。详见 §3.4。注意 Checkbox / Radio 在 1.2.9 末次修订中已从 frontend 层提升到 base 层(§3.1表单区),原因:pvq-wp 后台只enqueue(['admin']),frontend 层 CSS 后台不加载;二者是 WP 后台原生表单控件,须与 Switch/Input/Field/Select 同归 base 层(pvq-ui.css)。 - 旧插件名(
.pvq-btn-primary、.pvq-card-header、.pvq-connection-status等)不在本表,仅在《组件提取对照表.md》§6 作为迁移映射出现。
2. 设计令牌(:root 全集,base 层 pvq-ui.css)
取值以 wolai
admin-settings.css:11-62为基线;标注【合并】的为从 pvq-wp / threads 吸收(库首版新增)。库是纯令牌提供方,不假设--pvq-theme-*存在。令牌只加不删(见《项目规则》§2.4)。
2.1 主色系(森林绿)
| 令牌 | 值 | 说明 |
|---|---|---|
--pvq-primary |
#608062 |
主色 |
--pvq-primary-hover |
#4f6b51 |
主色 hover |
--pvq-primary-light |
rgba(96,128,98,0.08) |
主色浅底 |
--pvq-primary-soft |
rgba(96,128,98,0.12) |
主色柔底 |
--pvq-primary-glow |
rgba(96,128,98,0.20) |
主色辉光(focus / 阴影) |
--pvq-primary-gradient |
linear-gradient(135deg,#608062,#7a9e7c) |
主色渐变 |
--pvq-primary-gradient-hover |
linear-gradient(135deg,#4f6b51,#6b8e6d) |
主色渐变 hover |
2.2 语义色
| 令牌 | 值 | 说明 |
|---|---|---|
--pvq-success |
#4a8c5c |
成功 |
--pvq-success-light |
rgba(74,140,92,0.08) |
成功浅底 |
--pvq-danger |
#c45454 |
危险 |
--pvq-danger-light |
rgba(196,84,84,0.08) |
危险浅底 |
--pvq-warning |
#c49a2e |
警告 |
--pvq-warning-light |
rgba(196,154,46,0.08) |
警告浅底 |
--pvq-info |
#5a8a9a |
信息 |
--pvq-info-light |
rgba(90,138,154,0.08) |
信息浅底 |
2.3 中性色
| 令牌 | 值 | 说明 |
|---|---|---|
--pvq-bg |
#f4f5f2 |
页面背景 |
--pvq-surface |
#ffffff |
卡片 / 表面 |
--pvq-surface-hover |
#fafaf8 |
表面 hover |
--pvq-border |
#dfe3dc |
边框 |
--pvq-border-light |
#eaecea |
浅边框 / 分隔 |
--pvq-border-strong【v1.2.9】 |
#cdd2db |
悬停 / 聚焦时的稍深边框(前端组件 Bookmark、Search 等) |
--pvq-text |
#1e2a1f |
主文本 |
--pvq-text-secondary |
#5c6b5e |
次文本 |
--pvq-text-muted |
#94a396 |
弱文本 |
2.4 圆角
| 令牌 | 值 |
|---|---|
--pvq-radius-sm |
8px |
--pvq-radius |
12px |
--pvq-radius-lg |
16px |
--pvq-radius-xl |
20px |
--pvq-radius-pill【合并 pvq-wp】 |
999px |
2.5 阴影
| 令牌 | 值 |
|---|---|
--pvq-shadow-sm |
0 1px 3px rgba(30,42,31,0.04) |
--pvq-shadow |
0 2px 8px rgba(30,42,31,0.06) |
--pvq-shadow-md |
0 4px 20px rgba(30,42,31,0.08) |
--pvq-shadow-lg |
0 8px 32px rgba(30,42,31,0.12) |
--pvq-shadow-primary |
0 4px 16px rgba(96,128,98,0.25) |
2.6 缓动与过渡
| 令牌 | 值 |
|---|---|
--pvq-ease |
cubic-bezier(0.4,0,0.2,1) |
--pvq-ease-bounce |
cubic-bezier(0.34,1.56,0.64,1) |
--pvq-ease-magnet |
cubic-bezier(0.34,1.3,0.55,1) |
--pvq-ease-smooth |
cubic-bezier(0.25,0.1,0.25,1) |
--pvq-transition |
all 0.25s var(--pvq-ease) |
--pvq-transition-fast |
all 0.15s var(--pvq-ease) |
--pvq-transition-slow |
all 0.4s var(--pvq-ease-smooth) |
2.7 尺寸补充
| 令牌 | 值 | 说明 |
|---|---|---|
--pvq-input-h【合并 threads】 |
40px |
输入控件高度基准 |
--pvq-input-icon-size【v1.2.8】 |
14px |
输入框内图标字号,同步 .pvq-input__icon { font-size };参与图标缩进 calc 推导 |
--pvq-input-icon-offset【v1.2.8】 |
12px |
输入框内图标距左边界距离,同步 .pvq-input__icon { left };参与图标缩进 calc 推导 |
--pvq-input-icon-gap【v1.2.8】 |
12px |
图标盒右界与输入文字的最小安全间隙;FA 7.2.0 给 .fas 强制 width:1.25em 使图标盒加宽,故需抬到 12px(详见 §3.1 Input 条目「FA 7.2.0 图标盒宽适配」) |
2.8 v1.4.0 新增令牌(同值迁移 + 补齐被引用却缺失的令牌)
来源:H1「base/admin 层硬编码色值令牌化」与缺失令牌审计。全部为同值迁移(除
--pvq-text-strong见下),视觉不变;令牌只加不删(§2.4 精神)。
| 令牌 | 值 | 说明 / 原字面值 |
|---|---|---|
--pvq-radius-md |
8px |
补齐:.pvq-table 早已引用 var(--pvq-radius-md, 8px)、文档也写 --pvq-radius-md,但 :root 从未定义它;现正式登记 |
--pvq-surface-alt |
#f8f9f6 |
补齐:.pvq-collapse__header 等引用 var(--pvq-surface-alt, #f8f9f6),且有一处无兜底导致背景静默失效;现定义于 :root |
--pvq-text-strong |
#1e2a1f |
补齐并纠色:原为 var(--pvq-text-strong, #0b1b2f / #1f3a4b / #0b1e2b),兜底值是蓝调(wolai 蓝 demo 残留),与森林绿主色系冲突;现统一为与 --pvq-text 同值 |
--pvq-border-hover |
#c8d0c6 |
原字面值(按钮 / 次级按钮 hover 边框) |
--pvq-border-hover-strong |
#b8c4b9 |
原字面值(输入类控件 hover 边框:Input / Textarea / Affix / Select / ColorField) |
--pvq-surface-active |
#f8f9f7 |
原字面值(按钮 hover 底色,与 --pvq-surface-hover 不同值,故单列) |
--pvq-primary-alt |
#7a9e7c |
主色渐变的第二停靠色(原写死在 --pvq-primary-gradient 与 help 背景渐变里) |
--pvq-danger-hover |
#b34747 |
原字面值(.pvq-btn--armed hover 底色/边框) |
--pvq-warning-strong |
#8a6d14 |
原字面值(.pvq-status--warning 文字色,深琥珀) |
--pvq-warning-gradient |
linear-gradient(135deg,#f59e0b,#d97706) |
原字面值(.pvq-btn--warning 底色) |
--pvq-warning-gradient-hover |
linear-gradient(135deg,#d97706,#b45309) |
原字面值(warning hover) |
--pvq-warning-shadow |
rgba(217,119,6,0.3) |
原字面值(warning hover 投影) |
--pvq-toast-offset-x / --pvq-toast-offset-y |
20px |
补齐:Toast 文档称「布局令牌默认 20px」,此前只是 var() 兜底值、并非真实令牌;现定义于 :root,后台覆写 body.wp-admin{--pvq-toast-offset-y:44px} 照旧生效 |
同值迁移的实现方式:语义色的深浅派生(主色/成功/危险/警告/信息的 4%~28% 半透明底与边框)一律改写为
color-mix(in srgb, var(--pvq-<语义色>) N%, transparent)。在 sRGB 下与等价rgba()逐位相同,但改语义色令牌时派生色自动跟随,不再出现「改了主色、边框还是旧色」的问题。
3. 组件清单(按层)
层说明:
pvq-ui(base) 全场景;pvq-ui-admin/pvq-ui-editor/pvq-ui-frontend为场景层,依赖 base。
3.1 Base 层(pvq-ui.css)
按钮 Button · stable
- 类:
.pvq-btn - 修饰符:
--primary--secondary--danger--warning--ghost--sm--icon - 规格:圆角 9px · 字重 550 · 8/18 padding · 默认透明边框 hover 显现;primary 带渐变底 + 微阴影
- 组合:
.pvq-btn-group(按钮组,右对齐) - 删除按钮:复用
.pvq-btn--danger+fa-trash图标;破坏性操作建议加data-pvq-confirm二次确认(见下「删除按钮二次确认」) - 示例:
<button class="pvq-btn pvq-btn--primary"><i class="fas fa-save"></i> 保存</button> <div class="pvq-btn-group"> <button class="pvq-btn pvq-btn--secondary">取消</button> <button class="pvq-btn pvq-btn--primary">保存</button> </div> <!-- 删除按钮:文字版 / 图标-only 版 / 小号版 --> <button class="pvq-btn pvq-btn--danger"><i class="fas fa-trash"></i> 删除</button> <button class="pvq-btn pvq-btn--danger pvq-btn--icon"><i class="fas fa-trash"></i></button> <button class="pvq-btn pvq-btn--danger pvq-btn--sm"><i class="fas fa-trash"></i> 删除</button>
删除按钮二次确认(破坏性操作防护)· stable(1.2.0 新增行为)
- 行为:给任意按钮加
data-pvq-confirm="确认文案",库 JS 接管二次确认,避免误触删除 / 整页表单提交。任意.pvq-btn(不限于 danger)均可加。 - 交互(库 JS,捕获阶段
preventDefault+stopPropagation,见下「WordPress 注意」):- 首次点击:仅进入「确认态」——按钮就地变为实色危险红(
.pvq-btn--armed)+ 文案替换为确认语(如「确定删除?」),不触发原行为;设 3 秒自动取消。 - 确认态内再次点击:恢复外观并放行原行为(表单提交 / 插件自有
click监听照常执行)。 - 超时(3s)/ 按
Esc/ 点击页面其它处:自动取消,恢复原样。
- 首次点击:仅进入「确认态」——按钮就地变为实色危险红(
- 修饰符:
.pvq-btn--armed(确认态实色红,库自动加 / 去,插件勿手写)。 - 示例:
<button class="pvq-btn pvq-btn--danger" data-pvq-confirm="确定删除该项?"> <i class="fas fa-trash"></i> 删除 </button> - WordPress 注意:若按钮位于 WP
<form>内(如upload.php),首次点击由库在捕获阶段preventDefault,避免整页重载;确认态内第二次点击才放行。插件无需额外处理。 - 设计意图:破坏性操作统一防护,各插件不重复造轮子;纯
data-*增强,不破坏既有按钮样式与提交逻辑。
卡片 Card · stable
- 类:
.pvq-card - 子元素:
.pvq-card__header.pvq-card__icon.pvq-card__icon--{primary,success,warning,info,danger}.pvq-card__title.pvq-card__desc.pvq-card__action - 示例:
<div class="pvq-card"> <div class="pvq-card__header"> <span class="pvq-card__icon pvq-card__icon--primary"><i class="fas fa-cog"></i></span> <div> <h3 class="pvq-card__title">连接设置</h3> <p class="pvq-card__desc">配置账号信息</p> </div> </div> <div class="pvq-card__action"> <button class="pvq-btn pvq-btn--primary">保存</button> </div> </div>
表单 Field / Input · stable
-
类:
.pvq-field.pvq-field__label.pvq-field__help.pvq-field__error.pvq-field__success.pvq-input.pvq-input__wrap.pvq-input__wrap--has-icon.pvq-input__icon.pvq-input__toggle;附加变体:前后缀.pvq-affix-group.pvq-affix.pvq-affix--suffix、输入组.pvq-input-group.pvq-input-group__btn(.pvq-input-group__btn--ghost)、清除.pvq-input__clear+.pvq-input__wrap--has-clear、密码显隐切换.pvq-input__toggle+.pvq-input__wrap--has-toggle(由pvq-ui.js自动初始化,切换type=password/text) -
校验状态(行内校验,纯 CSS、零 JS):给
.pvq-field加.pvq-field--error/.pvq-field--success即切换输入框边框色与 focus 辉光(红/绿),并配.pvq-field__error(红色错误文案槽,常驻红字,配fa-circle-exclamation)或.pvq-field__success(绿色成功文案槽,常驻绿字,配fa-circle-check,与错误槽完全对称);.pvq-field__label--required在 label 后追加红色*必填标记。错误态须「红字 + 红框 + 红 focus 辉光」一整套,缺一不可。成功态用.pvq-field__success而非.pvq-field__help,避免与帮助文案语义重载、且二者可并存。 -
选择器特异性:覆盖 input 边框/辉光的规则一律写成
input.pvq-input.pvq-input(0,3,1),压过库默认input.pvq-input.pvq-input(0,2,1),否则 error/success 边框/辉光不变色(同components.json校验状态 demo)。 -
示例:
<div class="pvq-field"> <label class="pvq-field__label">API Token</label> <div class="pvq-input__wrap pvq-input__wrap--has-icon"> <i class="pvq-input__icon fas fa-key"></i> <input class="pvq-input" type="text" placeholder="请输入"> </div> <p class="pvq-field__help">在设置页获取你的 Token。</p> </div> -
校验状态示例(error / success + 必填):
<div class="pvq-field pvq-field--error"> <label class="pvq-field__label pvq-field__label--required">邮箱地址</label> <input class="pvq-input" type="text" value="not-an-email"> <p class="pvq-field__error"><i class="fas fa-circle-exclamation"></i> 请输入有效的邮箱地址</p> </div> <div class="pvq-field pvq-field--success"> <label class="pvq-field__label">数据库连接</label> <input class="pvq-input" type="text" value="mysql://127.0.0.1:3306"> <p class="pvq-field__success"><i class="fas fa-circle-check"></i> 连接测试通过</p> </div> -
附加变体(前后缀 / 输入组 / 清除 / 密码显隐切换,纯 CSS 零 JS 除外 toggle):
- 前后缀单位(joined segment):
.pvq-affix-group包.pvq-affix(前缀,默认)或.pvq-affix--suffix(后缀),内部<input class="pvq-input">自动去边框 / 去圆角,只剩外层框 + 分隔线。常用于https://前缀、px/%/MB单位后缀。 - 输入组(input + 按钮):
.pvq-input-group内放<input class="pvq-input">+<button class="pvq-input-group__btn">(配--ghost幽灵绿描边),横向组合用于复制 / 搜索。 - 清除按钮(✕):在
.pvq-input__wrap上加.pvq-input__wrap--has-clear,内部放<button class="pvq-input__clear">(绝对定位在右侧、复用 wrap 的position:relative),一键清空;padding-right自动让位给清除按钮。 - 密码显隐切换(眼睛):在
.pvq-input__wrap上加.pvq-input__wrap--has-toggle,内部放<button class="pvq-input__toggle" type="button" aria-label="显示密码">(绝对定位在右侧),由pvq-ui.js自动初始化,点击切换<input type="password">↔<input type="text">并切换图标fa-eye↔fa-eye-slash;padding-right自动让位给切换按钮,避免密码文本与眼睛重叠。 - 特异性:affix-group 内部 input、has-clear / has-icon / has-toggle 的
padding一律写成input.pvq-input.pvq-input(0,3,1)压过库默认输入样式(0,2,1),否则内部 input 边框残留(三重框)或图标 / 清除按钮 / 切换按钮压字。 - 【v1.2.8】FA 7.2.0 图标盒宽适配:FA 7.2.0 给所有
.fas强制width: var(--fa-width, 1.25em)+text-align: center,图标盒宽 =--pvq-input-icon-size(14px) × 1.25 = 17.5px(旧版 FA 无此约束、盒宽≈字形宽)。.pvq-input__icon定位于left:12px,图标右界落在12 + 17.5 = 29.5px;原padding-left/right:36px给文字/切换按钮仅留36 - 29.5 = 6.5px间隙,宽字形(fa-id-badge/fa-envelope)会压字。v1.2.8 改为padding-left/right: calc(var(--pvq-input-icon-offset) + var(--pvq-input-icon-size) * 1.25 + var(--pvq-input-icon-gap))=12 + 17.5 + 12 = 41.5px → 42px,间隙恢复 12.5px。图标几何用--pvq-input-icon-*令牌化,FA 改图标宽度系数时只改1.25一处即可(详见 §2.7 令牌表)。 - 示例(前后缀 + 输入组 + 清除):
<!-- 前后缀 --> <div class="pvq-field"> <label class="pvq-field__label">站点地址</label> <div class="pvq-affix-group"> <span class="pvq-affix">https://</span> <input class="pvq-input" type="text" value="example.com"> </div> </div> <div class="pvq-field"> <label class="pvq-field__label">缩略图宽度</label> <div class="pvq-affix-group"> <input class="pvq-input" type="text" value="320" style="text-align:right"> <span class="pvq-affix pvq-affix--suffix">px</span> </div> </div>
``` - 前后缀单位(joined segment):
长文本输入框 Textarea · stable
- 类:
.pvq-textarea(配合.pvq-field容器使用),变体.pvq-textarea--sm(小号)。 - 与
.pvq-input同源视觉:边框 1.5px、--pvq-radius-sm圆角、:focus主色边框 +box-shadow辉光、::placeholder弱色;resize: vertical仅允许纵向拖拽,禁横向。 - 选择器特异度:
textarea.pvq-textarea.pvq-textarea(0,2,1),与库其它表单控件一致,压过 WP 核心(WP 仅对textarea有通用 (0,0,1) 规则,被压过)。 - 示例:
<div class="pvq-field"> <label class="pvq-field__label" for="desc">备注</label> <textarea class="pvq-textarea" id="desc" placeholder="请输入详细描述…"></textarea> <p class="pvq-field__help">支持多行,可纵向拖拽调整高度。</p> </div>
选择器 Select(自定义下拉,渐进增强原生 select)· experimental
- 类:
.pvq-select(包裹原生<select>,库自动初始化).pvq-select__trigger.pvq-select__text.pvq-select__arrow.pvq-select__dropdown.pvq-select__option.pvq-select--open.pvq-select__option--selected.pvq-select__option--disabled.pvq-select--sm(紧凑变体) - 结构:
.pvq-select内放一个原生<select>(保留其name/value/disabled,表单照常提交);库 JS 自动把它增强为自定义下拉,原生 select 仅视觉隐藏、DOM 仍存在,选中即同步原生 select 的value并派发change。 - 交互(库 JS,原生事件委托、无 jQuery):点击 trigger 开/关;打开时箭头翻转、空间不足自动向上弹(flip)、右边界贴合、滚动/缩放重定位;键盘 Enter/Space 切换、ArrowDown 打开、Esc 关闭;点击外部关闭;同时只开一个。
- 可访问性:首版
experimental为简易键盘(triggertabindex=0+ Enter/Space/Esc),role=listbox/option、aria-expanded、方向键在选项间移动留待 stable 时补齐。 - 下拉面板挂
<body>(position:fixed):为绕过 WP metabox 的overflow:hidden裁剪,非 jQuery 特性,原生版同样如此。 - 变体:
.pvq-select--sm(紧凑):trigger 高30px/ 字号13px/padding:5px 10px,并min-width:0解除库默认min-width:160px,适配 WP 后台 tablenav / bulkactions / 媒体工具栏等密集行;下拉面板min-width:120px。纯 CSS 修饰,pvq-ui.js只扫描.pvq-select,--sm不影响初始化。特异性.pvq-select--sm .pvq-select__trigger(0,2,0)高于库.pvq-select__trigger(0,1,0),无需!important。 - 变体:
.pvq-select--glass(玻璃磨砂下拉,v1.2.10 前端装饰):容器加pvq-select--glass,body 级下拉面板即半透明磨砂。机制要点:面板由 JS 渲染并挂<body>、无父级可继承容器类,故 JS 在打开时检测容器上的pvq-select--glass并把状态带到面板(加.pvq-select__dropdown--glass),不能靠后代选择器。样式:半透明白rgba(255,255,255,.52)+backdrop-filter: blur(20px) saturate(1.4)(@supports检测-webkit-/标准前缀,不支持时退回rgba(255,255,255,.72)高不透明度,保证文字可读);玻璃态下选项 hover 用--pvq-primary-light、选中用--pvq-primary-soft(半透明绿系,补偿透明造成的对比损失)。装饰性变体,需背后有彩色内容才显 blur 效果(后台白底上仅见轻微通透感)。默认下拉保持纸面不透明,不影响存量调用。 - 示例:
<div class="pvq-select"> <select name="threads_sync_settings[mode]"> <option value="auto">自动同步</option> <option value="manual" selected>手动同步</option> <option value="off">关闭</option> </select> </div>
开关 Switch(语义化,纯 CSS)· stable
- 结构:
.pvq-switch包<input type="checkbox" class="pvq-switch__input">+<span class="pvq-switch__slider"> - 行布局:
.pvq-switch-row.pvq-switch-row__label.pvq-switch-row__desc - 行为:纯 CSS,由
:checked控制,零 JS;可访问性最好(真实 checkbox)。 - 示例:
<div class="pvq-switch-row"> <div> <div class="pvq-switch-row__label">启用同步</div> <div class="pvq-switch-row__desc">开启后自动同步内容</div> </div> <label class="pvq-switch"> <input type="checkbox" class="pvq-switch__input" checked> <span class="pvq-switch__slider"></span> </label> </div>
微交互动画(档 2,纯 CSS)
- 滑块位移由
left改为transform: translateX(var(--x)):GPU 加速、不重排;配合--pvq-ease-bounce弹簧缓动,开/合"弹一下"。 - 圆点用
::before伪元素(与演示 demo 一致);CSS 变量--x(位移)和--s(缩放)定义在.pvq-switch__slider上::checked改--x:20px、:hover改--s:1.12、:active改--s:0.9。圆点::before读var(--x)/var(--s)组合为单一transform: translateX(var(--x)) scale(var(--s))。transition拆为独立属性transition-property/duration/timing-function(非简写),防 WordPress 全局*::before { transition: all … }覆盖弹簧缓动。 - 开/关换色用实色
--pvq-primary(可transition平滑过渡);不再用--pvq-primary-gradient(CSS 无法对gradient做过渡,旧版为瞬间硬切)。 - 开合光晕:滑块
box-shadow在:checked时播放一次性pvq-switch-ring扩散(向外扩 9px 柔光环),起止落回常驻 glow,纯视觉反馈(与演示 demo 一致)。 - 不开态图标,仅以位置 + 颜色 + 光晕表达状态。
- 全部动效由库全局
@media (prefers-reduced-motion: reduce)统一降级(动画/过渡即时,无滑动、无缩放)。
勾选框 Checkbox · stable(1.2.9 并入;末次修订由 frontend 层提升至 base 层)
- 归属层:base 层(
pvq-ui.css)。原因:pvq-wp 后台仅enqueue(['admin']),pvq-ui-admin依赖 base,故 base 必随后台加载;Checkbox 是 WP 后台原生表单控件,须与 Switch/Input/Field/Select 同归 base(1.2.9 曾误置于 frontend 层,末次修订已提升)。 - 结构:
.pvq-cb-list(布局容器,仅display:flex; flex-direction:column; gap; margin-top,不再承载令牌)>label.pvq-cb-item(独立可用:裸<label class="pvq-cb-item">包裹原生<input>+.pvq-custom-check即可,无需.pvq-cb-list父级)> 隐藏原生<input type="checkbox">+span.pvq-custom-check(.pvq-cb-box+span.pvq-cb-mark✓)+span.pvq-cb-text。 - 令牌已提至
:root(全局默认值):--pvq-cb-size(32px)/--pvq-cb-radius(10px)/--pvq-cb-bg(#fff)/--pvq-cb-border/--pvq-cb-checked-bg/--pvq-cb-checked-border/--pvq-cb-checked-shadow(0 6px 14px …)/--pvq-cb-checked-dark/--pvq-cb-ghost-bg/--pvq-cb-ghost-border/--pvq-cb-ripple-bg/--pvq-cb-ripple-ring/--pvq-cb-ripple-checked-bg/--pvq-cb-ripple-spread,均派生自--pvq-primary。原因:原令牌写在.pvq-cb-list内,裸.pvq-cb-item(无.pvq-cb-list父容器)时var(--pvq-cb-size)算空 → 勾框尺寸崩掉;提到:root后独立.pvq-cb-item也能正常工作。--sm/--lg修饰符仍在其作用域覆盖默认值。--pvq-cb-mark-size不入:root(靠var(...,18px)兜底 + 变体覆盖)。 - 三态
:checked/:indeterminate(部分选中,列表页"全选"主框):命中:indeterminate时.pvq-cb-box绿底 + 隐藏 ✓ 字形 +.pvq-cb-box::after画一条白色横线(base/ghost/ripple 变体下.pvq-cb-box均无::after,安全不冲突);WP "全选"主框由 JS 设indeterminate属性自动命中。 - 三变体:
pvq-cb-variant-strike(勾选后文字删除线)、pvq-cb-variant-ghost(透明底圆角)、pvq-cb-variant-ripple(圆形 + 扩散波纹);弹性打钩(cubic-bezier(.34,1.56,.64,1))+ 整框脉冲;prefers-reduced-motion关闭动画。 - 尺寸变体(在
.pvq-cb-list上加):--sm(24px)/ 默认(32px)/--lg(40px),令牌--pvq-cb-size/--pvq-cb-radius/--pvq-cb-mark-size控制。 - 示例:
<div class="pvq-cb-variant-strike"><div class="pvq-cb-list"><label class="pvq-cb-item"><input type="checkbox" checked><span class="pvq-custom-check"><span class="pvq-cb-box"></span><span class="pvq-cb-mark">✓</span></span><span class="pvq-cb-text">默认选中</span></label></div></div> <!-- 尺寸:<div class="pvq-cb-list pvq-cb-list--sm"> … </div> --> <!-- 三态:JS 给 input 设 .indeterminate=true → 命中 :indeterminate(横线) -->
单选按钮 Radio · stable(1.2.9 并入;末次修订由 frontend 层提升至 base 层)
- 归属层:base 层(
pvq-ui.css)。原因同 Checkbox(WP 后台原生控件,须随 admin 依赖的 base 加载;1.2.9 曾误置于 frontend 层,末次修订已提升)。 - 结构:
.pvq-rb-group(布局容器,仅display:flex; flex-direction:column; gap; margin-top,不再承载令牌)>label.pvq-rb-item> 隐藏原生<input type="radio">+span.pvq-custom-radio(.pvq-rb-outer+span.pvq-rb-dot) +span.pvq-rb-label。 - 令牌已提至
:root(全局默认值):--pvq-rb-size(32px)/--pvq-rb-outer-border/--pvq-rb-dot/--pvq-rb-checked-bg/--pvq-rb-checked-border/--pvq-rb-ring/--pvq-rb-checked-dark/--pvq-rb-ripple-checked-bg/--pvq-rb-ripple-spread/--pvq-rb-base-bg,均派生自--pvq-primary。原因同 Checkbox。--pvq-rb-dot-size不入:root(靠var(...,14px)兜底 + 变体覆盖)。 - 四变体:
pvq-rb-variant-card(选中高亮整行,:has(input:checked))、pvq-rb-variant-ghost(透明底 + 白点)、pvq-rb-variant-ripple(圆形 + 扩散波纹)、pvq-rb-variant-solid(纯色填充);内点弹性弹入 + 整钮脉冲;prefers-reduced-motion关闭动画。 - 尺寸变体(在
.pvq-rb-group上加):--sm(24px)/ 默认(32px)/--lg(40px),令牌--pvq-rb-size/--pvq-rb-dot-size控制。 - 示例:
<div class="pvq-rb-variant-card"><div class="pvq-rb-group"><label class="pvq-rb-item"><input type="radio" name="g" checked><span class="pvq-custom-radio"><span class="pvq-rb-outer"></span><span class="pvq-rb-dot"></span></span><span class="pvq-rb-label">标准套餐</span></label></div></div>
状态指示 Status · stable
- 类:
.pvq-status--{success,warning,error}.pvq-status__dot - 示例:
<span class="pvq-status pvq-status--success"><span class="pvq-status__dot"></span> 已连接</span>
徽标 Badge · stable【新增】
- 类:
.pvq-badge;可选修饰符--primary等(默认主色浅底) - 示例:
<span class="pvq-badge">v1.3.18</span>
横幅 Banner(原 connection-status)· stable
- 类:
.pvq-banner--{success,danger,warning,info}.pvq-banner__dot.pvq-banner__title.pvq-banner__text.pvq-banner__close(可关闭,本次新增) - 映射:connected→
--success、disconnected→--danger、unconfigured→--warning - 可关闭(新增):待办 / 提醒类横幅末尾放
<button type="button" class="pvq-banner__close" data-pvq-banner-close aria-label="关闭">✕</button>,库 JSinitBanners()(随initAll自动调用、幂等,用data-pvq-banner-init防重复)接管点击:加--closing→ 动画结束移除节点 → 派发pvq-banner:close(detail: { banner })供插件写入关闭记忆(如user_meta/ localStorage)。纯声明式,插件无需写 JS;不含__close的横幅行为完全不变(向后兼容)。 - 关闭记忆由插件持久化,库不碰任何 storage(避免跨插件猜测键名与越权)。
- 示例:
<div class="pvq-banner pvq-banner--warning"> <span class="pvq-banner__dot"></span> <div><div class="pvq-banner__title">尚未配置 Token</div><div class="pvq-banner__text">前往「设置 → 连接」完成授权。</div></div> <button type="button" class="pvq-banner__close" data-pvq-banner-close aria-label="关闭">✕</button> </div> <script>/* 记忆(示例):*/ document.addEventListener('pvq-banner:close', function (e) { /* saveClosed(e.detail.banner.dataset.pvqBannerKey) */ });</script>
提示 Alert(原 test-result)· stable
- 类:
.pvq-alert--{success,error,loading}+ 显隐类.pvq-alert--show - 示例:
<div class="pvq-alert pvq-alert--show pvq-alert--success"><i class="fas fa-check"></i> 测试通过</div>
浮层通知 Toast · experimental【新增:回流自 pvq-weixinyuedu,待发版固化】
与 Alert / Banner 的分工:toast 只承载「一次操作的即时结论」(短句、短暂停留、自动消失)。结果是一组数据→用页面内常驻区域(如
.pvq-meta-list),toast 只说一句结论;长任务进行中→内联.pvq-alert--loading;常驻待办→可关闭的.pvq-banner。
- 类:
.pvq-toast-layer(容器).pvq-toast--{success,error,warning,info}(--danger为--error别名)--leaving(离场态,JS 添加).pvq-toast__icon.pvq-toast__body.pvq-toast__title.pvq-toast__desc.pvq-toast__close - 容器由库 JS 自动创建(首次
PVQUI.toast()/initToasts()时挂到<body>,幂等、全局唯一),因此 JS 未加载时无 DOM 残留(不对静态 HTML 做破坏性假设)。 - 层级
z-index: 100002:刻意高于.pvq-modal遮罩(100001)。既有三档为 99999 取色面板 / 100000 下拉 / 100001 遮罩;toast 必须压过遮罩,否则「弹窗确认 → 删除成功」这条最高频链路在遮罩关闭前看不到结果反馈。 - 设计原则:形状归库、颜色归令牌。组件只定义
--pvq-toast-accent(四种变体分别赋--pvq-success/danger/warning/info),左侧色条与图标色彩全走它,零硬编码。布局令牌--pvq-toast-offset-y/--pvq-toast-offset-x,默认20px为中性值(前台无 admin bar 也不留多余空白);WP 后台由消费方在body上覆写--pvq-toast-offset-y: 44px(≤782px 视口 admin bar 46px)。 - API:
PVQUI.toast(options)→ 返回单条实例对象(含el/close(reason))。options:
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
type |
string | 'info' |
success / error / warning / info |
title |
string | 必填 | 主文案(走 textContent,不接受 HTML,防 XSS) |
desc |
string | — | 次要文案(同样 textContent) |
icon |
string | 按 type 取 FA 类 | 如 'fas fa-circle-check' |
duration |
number | success/info 3000、warning 5000、error 8000 |
毫秒;0 = 不自动关闭(须手动关) |
- 行为:同屏最多 4 条,超出时最旧一条立即离场(
reason: 'displace');鼠标悬停暂停倒计时、移开继续;点击__close立即关闭(reason: 'close');prefers-reduced-motion下无位移缩放(animationend兜底定时器保证节点一定被回收)。 - 事件(均冒泡):
pvq-toast:open/pvq-toast:close,detail: { toast, el, type, reason }。 - 可访问性:容器
role="region" aria-label="通知"(容器不挂aria-live——容器插入瞬间被朗读会异常);单条 success/info 用role="status"(aria-live="polite"),error/warning 用role="alert"(aria-live="assertive")。 - 声明式触发(可选用法,便于后端渲染 / 官网 demo):任意元素加
data-pvq-toast即由initToasts()接管,点击触发;参数读data-pvq-toast-type/-title(缺省用元素文本)/-desc/-duration。避免 inline handler,与data-pvq-confirm、data-pvq-modal-open同范式。 - 明确不做:点击跳转 / 承载操作按钮 / 进度条型 / 声音或桌面通知。
- 示例:
<!-- JS 调用 --> <script> PVQ_UI_ToastExample(); function PVQ_UI_ToastExample() { PVQUI.toast({ type: 'success', title: '设置已保存' }); PVQUI.toast({ type: 'error', title: '连接失败', desc: 'Token 无效或已过期', duration: 0 }); } </script> <!-- 声明式 --> <button type="button" class="pvq-btn pvq-btn--primary" data-pvq-toast data-pvq-toast-type="success" data-pvq-toast-title="已同步 12 条">触发通知</button> - 幂等提醒:
initAll()同时绑定在DOMContentLoaded与window resize上,故initToasts()只负责「确保容器存在」,绝不清理正在显示的 toast(否则窗口一缩放通知就被抹掉)。
锚点浮层 Popover · experimental【新增:回流自 pvq-weixinyuedu,待发版固化】
与 Card / Collapse / Confirm Modal / Toast 的分工:popover 以某元素为锚、脱离文档流按需显隐。
card是常驻内容容器(无定位与开合)、collapse是原地展开会撑高文档流造成布局位移、confirm-modal是模态阻断交互、toast固定在角落不锚定触发元素——四者都不能替代「锚定某元素的气泡」(术语解释 / 作者卡 / 预览 / 迷你详情)。
- 类:
.pvq-popover(浮层本体).pvq-popover__body(内容区).pvq-popover__foot(脚注区,可选,border-top分隔).pvq-popover__arrow(可选小箭头);修饰符--open(打开态,库 JS 加)、--above(库 JS 判定的上方位置)。 - 开关契约只有两个状态:
hidden属性 = 彻底不显示(display:none);--open= 淡入显示。库只认这两个,不碰业务。 - 定位:
position: fixed,坐标由库 JS 用getBoundingClientRect()算出后写内联top/left。刻意不用 absolute——那必须假定业务容器是定位上下文,而那是业务的自由,库不该假定。默认贴锚点下方,下方放不下且上方够高时自动翻转并加--above;水平与垂直双向夹取,不飞出视口。 - 设计原则:形状归库、颜色归令牌。只暴露布局令牌
--pvq-popover-width(默认min(24rem, calc(100vw - 2rem)))与--pvq-popover-z(默认90),色值全走--pvq-*,零硬编码。浮层显式声明font-size/line-height(防主题放大正文),内容区用.pvq-popover .pvq-popover__body(0,2,0)压过主题.entry-content p(0,1,1)且不引用主题类。 - API:
PVQUI.popover(anchor, options)→ 实例{ el, anchor, open(), close(), toggle(), destroy() }。options:
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
content |
string | Element | — | 字符串按 HTML 插入(调用方须自行确保可信,不得拼未转义的用户输入);传 DOM 节点则直接挂载 |
target |
Element | — | 既有 .pvq-popover 元素;不传则由库创建并挂到 <body>(destroy() 时一并移除) |
placement |
string | 'auto' |
auto(自动翻转)/ below / above |
gap |
number | 8 |
与锚点的间距(px) |
closeDelay |
number | 160 |
鼠标移开后延时关闭(ms),给移入浮层留时间 |
role |
string | 'note' |
库创建浮层时写入的 role |
onOpen / onClose |
function | — | 回调,入参为实例 |
-
行为:桌面
mouseenter/mouseleave(延迟closeDelay关闭);触屏(matchMedia('(hover: hover)')判定,不信伪悬停)改为点按开合;锚点focusin/focusout键盘可达;Escape关闭并把焦点交还锚点;点击浮层与锚点之外关闭;关闭有退出过渡(180ms,与 CSS.18s对齐)不掐断动画;锚点滚动(捕获阶段监听,含任意滚动容器)与窗口缩放时打开态重新定位;prefers-reduced-motion下无过渡与位移。 -
事件(均冒泡):
pvq-popover:open/pvq-popover:close,detail: { popover, el, anchor, reason }(reason为pointer/focus/click/escape/outside/api)。 -
可访问性:浮层
role="note"(不用tooltip——tooltip 语义要求「纯说明文本、不含可交互内容」,而本组件允许浮层内含链接等富内容);锚点tabindex="0"+aria-describedby="<浮层 id>"(库仅在缺失时补写、不覆盖既有值);组件不是模态,不做焦点陷阱与aria-modal。 -
声明式触发(便于后端渲染 / 官网 demo):锚点加
data-pvq-popover="<浮层 id>"即由initPopovers()接管(值为空时回退读aria-describedby);目标必须存在且带.pvq-popover类,以免误绑普通aria-describedby说明文本。声明式走默认参数,要定制用命令式。 -
幂等提醒:
initAll()同时绑定在DOMContentLoaded与window resize上,故同一浮层只初始化一次(实例挂el.__pvqPopover),document/window级监听(Escape / 外部点击 / scroll / resize)只绑一次(模块级popoverGlobalBound)。 -
已知边界:祖先带
transform/filter/backdrop-filter/will-change会成为position:fixed的包含块而致坐标偏移——库不移动浮层 DOM(最小侵入),这类容器里须把浮层放到该容器之外。 -
无 JS 边界:库默认即浮层态(不设
.pvq-js渐进分支),故 JS 缺席时浮层保持不可见;信息兜底由调用方提供(如<noscript>静态呈现)。 -
明确不做:业务内容槽(
__title/__icon等)、异步加载、自动消失计时、拖拽吸附、多层嵌套、position:absolute定位模式。 -
完整落库决策见
doc/开发文档/PVQ-UI回流落库-Popover锚点浮层.md。 -
示例(声明式):
<button type="button" tabindex="0" class="pvq-btn pvq-btn--ghost" data-pvq-popover="pvq-demo-pop" aria-describedby="pvq-demo-pop">悬停 / 点按我</button> <div class="pvq-popover" id="pvq-demo-pop" role="note" hidden> <div class="pvq-popover__body"><p>以元素为锚、脱离文档流、按需显隐的浮层。</p></div> <div class="pvq-popover__foot">术语解释 · 悬停查看</div> <span class="pvq-popover__arrow"></span> </div>
统计 Stat(原 cache-stat)· stable
- 类:
.pvq-stat-grid.pvq-stat.pvq-stat__value.pvq-stat__label - 示例:
<div class="pvq-stat-grid"> <div class="pvq-stat"><div class="pvq-stat__value">128</div><div class="pvq-stat__label">已同步</div></div> <div class="pvq-stat"><div class="pvq-stat__value">12</div><div class="pvq-stat__label">待处理</div></div> </div>
帮助 Help(原 help-card)· stable
- 类:
.pvq-help.pvq-help__icon.pvq-help__title.pvq-help__text - 示例:
<div class="pvq-help"> <i class="pvq-help__icon fas fa-lightbulb"></i> <div><div class="pvq-help__title">小贴士</div><div class="pvq-help__text">首次使用请先配置 Token。</div></div> </div>
范围 Range · stable(v1.2.10 增强:数值框可编辑)
-
类:
.pvq-range__groupinput.pvq-range.pvq-range__value.pvq-range__labels -
.pvq-range__value双形态(渐进增强,向后兼容):**<span>/.pvq-range__value**:只读显示(旧行为,拖动滑块由库 JS 写入textContent)。**<input type="number" class="pvq-range__value">:可直接输入数字**,失焦/回车/步进即回写滑块值;非法或超范围自动 clamp 到min/max并按step对齐。
-
JS 行为(双向实时联动,二者互不失效):
- 拖滑块 → 数值框:滑块
input事件写回框内。<input>写.value、<span>写.textContent——注意:对<input>必须写.value,textContent对 void element 无效,曾导致「拖滑块不更新输入框」的 bug(v1.2.10 修复)。 - 数值框编辑 → 滑块:输入过程中(
input事件)实时 clamp + step 对齐并更新滑块,但不改写框内文本(否则输入50时输完5就被改写、光标跳位);回车/步进器(change)与失焦(focusout)时才校正框内显示为合法值。内部用rangeSyncing标志避免派发事件回写打断输入。 - 回写滑块后对滑块派发原生
input/change,插件原有监听无需改动。字段识别靠.pvq-range__value的 tagName,无需额外属性或初始化。
- 拖滑块 → 数值框:滑块
-
CSS:
input.pvq-range__value继承原只读框视觉(绿底--pvq-primary-light、绿字、圆角 sm),并隐藏 number spinner(appearance:textfield+::-webkit-*-spin-button置 none),focus 加border-color: var(--pvq-primary)+--pvq-primary-glow辉光,宽度min-width:80px(可由插件覆)。 -
示例(只读 / 可编辑 两种写法):
<!-- 只读(原有写法,仍受支持) --> <div class="pvq-range__group"> <input type="range" class="pvq-range" min="1" max="100" value="50"> <span class="pvq-range__value">50</span> </div> <div class="pvq-range__labels"><span>慢</span><span>快</span></div> <!-- 可编辑(v1.2.10 新增:数值框直接改,回写滑块) --> <div class="pvq-range__group"> <input type="range" class="pvq-range" min="1" max="100" value="50"> <input type="number" class="pvq-range__value" min="1" max="100" step="1" value="50" aria-label="数值"> </div> <div class="pvq-range__labels"><span>慢</span><span>快</span></div>
二次确认弹窗 Confirm Modal · stable(v1.2.10 新增)
-
类:
.pvq-modal[data-pvq-modal].pvq-modal--open--busy--warning--primary;子元素.pvq-modal__backdrop.pvq-modal__panel__close__icon__title__desc__list__actions__cancel__confirm__spinner。 -
用途:破坏性 / 重要操作的弹窗式二次确认。与既有
data-pvq-confirm(按钮就地二次确认,1.2.0)互为补充、不冲突:就地确认适合表格行内删除等轻量场景,弹窗适合需要说明后果、列出影响对象、异步执行的重量级场景。 -
设计原则:形状归库、颜色归令牌。组件仅定义
--pvq-modal-accent(默认var(--pvq-danger)红,与库--armed二次确认态语义一致)与--pvq-modal-accent-light、--pvq-modal-radius(默认 24px);图标圆、清单圆点、确认按钮(含 hover 与投影)全部走 accent,零硬编码色值。变体--warning(黄)/--primary(森林绿)只换令牌,形状与结构不变。 -
结构契约:
.pvq-modal为position:fixed全屏遮罩容器(默认display:none,加--open才显形),内部依次为.pvq-modal__backdrop(点击关闭)+.pvq-modal__panel(role="dialog"aria-modal="true")→ 图标__icon→ 标题__title→ 描述__desc→ 可选清单__list→ 按钮组__actions(__cancel+__confirm,flex:1 1 0等宽)。 -
按钮实色 + 高特度(关键坑):确认按钮为实色 accent + 白字,用于「一眼识别动作性质」。因库基础样式是
button.pvq-btn.pvq-btn(0,3,1)且background: var(--pvq-surface),组件按钮必须写到 (0,4,1)(button.pvq-btn.pvq-modal__confirm.pvq-modal__confirm)才能压过,否则只看到彩色阴影、按钮本体是白的。取消按钮同理;hover 的color、:disabled的opacity、点击涟漪::before也需同特度接管。 -
JS 入口:
window.PVQUI.initConfirms()(initAll()自动调用,幂等):- 触发器
[data-pvq-modal-open="<弹窗id>"]→ 打开对应.pvq-modal; [data-pvq-modal-close](右上角 X / 取消按钮 / 遮罩)→ 关闭;[data-pvq-modal-confirm]→ 派发pvq-modal:confirm(detail:{ id, modal, trigger })后关闭。插件监听该事件执行真实操作(删除请求等),库只管 UI 不碰业务。- 派发
pvq-modal:open/pvq-modal:close。 - 异步场景:给确认按钮加
[data-pvq-modal-async],点击后按钮转 spinner + 禁用(防重复提交),由插件在业务完成后调用modal.closeModal()关闭;库不自动关闭。
- 触发器
-
无障碍:
role="dialog"+aria-modal+aria-labelledby;打开时默认聚焦取消按钮(防回车误触发破坏性操作);焦点陷阱(Tab/Shift+Tab 锁在弹窗内);Esc 关闭;关闭后焦点归还触发元素;滚动锁定(库在<html>上加.pvq-scroll-locked,关闭与pagehide时释放,bfcache 恢复时自愈复位)。尊重prefers-reduced-motion。 -
窄屏(≤480px)转贴底抽屉,按钮组
column-reverse(确认在上、更易点到)。 -
示例(最小结构):
<button class="pvq-btn pvq-btn--danger" data-pvq-modal-open="del-modal">删除</button> <div class="pvq-modal" id="del-modal" data-pvq-modal role="dialog" aria-modal="true" aria-labelledby="del-t"> <div class="pvq-modal__backdrop" data-pvq-modal-close></div> <div class="pvq-modal__panel"> <button class="pvq-modal__close" data-pvq-modal-close aria-label="关闭">✕</button> <div class="pvq-modal__icon"><i class="fas fa-triangle-exclamation"></i></div> <h3 class="pvq-modal__title" id="del-t">确认删除?</h3> <p class="pvq-modal__desc">此操作将永久删除 <strong>“项目报告 Q3”</strong>,且<strong>无法恢复</strong>。</p> <div class="pvq-modal__actions"> <button type="button" class="pvq-btn pvq-modal__cancel" data-pvq-modal-close>取消</button> <button type="button" class="pvq-btn pvq-modal__confirm" data-pvq-modal-confirm>确认删除</button> </div> </div> </div>// 插件接业务: document.addEventListener('pvq-modal:confirm', function (e) { if (e.detail.id !== 'del-modal') return; // …执行删除请求;异步场景用 data-pvq-modal-async + e.detail.modal.closeModal() });
分隔 Divider · stable
- 类:
.pvq-divider
可折叠卡片 Collapse · experimental【新增】
- 结构:
.pvq-collapse>button.pvq-collapse__header[aria-expanded]+.pvq-collapse__body>.pvq-collapse__inner - 箭头:
<i class="fa-solid fa-chevron-down pvq-collapse__arrow"></i>(FontAwesome),展开态旋转 180° 变主色 - 标题:浅灰底(
--pvq-surface-alt),展开时底边加阴影分隔 - 内边距:
.pvq-collapse__inner为padding: 16px 18px(顶部/底部 16px、左右 18px 与 header 对齐),展开后内容与 header 间距充足、不发挤(原顶部 12px 偏紧) - 行为:点击标题切换
--open类名;aria-expanded同步更新;展开态 JS 将body.style.maxHeight设为'none'(非scrollHeight+'px'),收起/展开过渡临时用 px、transitionend(仅max-height属性)后回到'none',保证高度动画平滑且内容异步变高不被固定 px 裁切 - 隐藏容器兼容:卡片位于
display:none选项卡内时,加载期scrollHeight量出 0 不再导致「假收起 / 点一下没反应」(v1.2.7 修复;原逻辑写死scrollHeight+'px'导致默认展开却显示收起) - 默认展开:
.pvq-collapse上加.pvq-collapse--open,JS 自动校准max-height为'none' - 多卡片可同时展开(非手风琴),互不影响
- JS 入口:
window.PVQUI.initCollapses()(initAll()自动调用) - 示例:
<div class="pvq-collapse" data-pvq-collapse> <button class="pvq-collapse__header" aria-expanded="false"> <span>标题文本</span> <i class="fa-solid fa-chevron-down pvq-collapse__arrow"></i> </button> <div class="pvq-collapse__body"> <div class="pvq-collapse__inner">内容...</div> </div> </div>
点击上传 Upload · experimental【新增】
- 结构:
.pvq-upload>input[type="file"].pvq-upload__input(隐藏) +button.pvq-upload__trigger+.pvq-upload__info>.pvq-upload__name+button.pvq-upload__clear - 行为:点击触发区 → 打开文件选择 → 选中后在下方显示文件名 + ✕ 清除按钮
- 布局变体:默认
column(trigger 在上、info 在下);加--inline改为row(align-items: center),整行回到单行高度,用于 WP 设置行与相邻行对齐。 - 清除按钮语义色:
.pvq-upload__clear(✕)默认color: var(--pvq-text-muted)、background: transparent(静音、退居次要,不与整行绿色糊在一起);hover /:focus-visible转为危险红color: var(--pvq-danger)+background: var(--pvq-danger-light),键盘聚焦同款outline: 2px solid var(--pvq-danger)。危险色仅在「意图发生那一刻」(hover/聚焦)出现,避免整行常驻红色告警;复用库--pvq-danger/--pvq-danger-light(与 banner/status/alert 一致)。 - 变体:
.pvq-upload--solid(实色按钮)、.pvq-upload--drop(大号拖放区风格)、.pvq-upload--inline(横排:trigger 与 info 同一行,适配设置行等高对齐;与--solid可叠加;不与--drop同用) - JS 入口:
window.PVQUI.initUploads()(initAll()自动调用),幂等初始化 - 示例:
<div class="pvq-upload" data-pvq-upload> <input type="file" class="pvq-upload__input"> <button type="button" class="pvq-upload__trigger"><i class="fa-solid fa-cloud-arrow-up"></i> 选择文件</button> <div class="pvq-upload__info"> <span class="pvq-upload__name"><i class="fa-solid fa-file"></i> <span class="pvq-upload__name-text"></span></span> <button type="button" class="pvq-upload__clear"><i class="fa-solid fa-times"></i></button> </div> </div>
搜索组件 Search · stable(base 层,1.2.8 新增)
-
类:
.pvq-search;结构:<i class="pvq-search__icon fas fa-magnifying-glass">(放大镜图标,绝对定位)+<input class="pvq-search__input">(内部 input,特异性input.pvq-search__input(0,2,1)压过 WP 核心)+ 可选<button class="pvq-search__clear">(清除 ✕,JS 控制显隐)+ 可选<button class="pvq-search__submit">(提交,joined 右段)+ 可选<i class="pvq-search__spinner fas fa-spinner fa-spin">(加载态 spinner)。 -
设计原则:形状归库、颜色归令牌。组件定义
--pvq-search-accent(默认var(--pvq-primary)绿),focus 边框/辉光/提交按钮底色全走它;hover 用color-mix(in srgb, accent 82%, #000)压暗(任意色可用,零硬编码)。库不内置 off-brand 色(蓝/橙由插件自覆盖--pvq-search-accent)。 -
功能变体(结构/行为):
--with-btn:右侧实心「搜索」按钮(joined 段,自带左分隔线),点击或回车提交。--with-filter:左侧复用库.pvq-select作范围段(标题/正文/作者…),与全站 Select 视觉一致;库 JS 自动增强(触发器 + body 级下拉),改选即带范围重搜。覆盖.pvq-select自身边框/圆角/辉光、仅留右侧分隔线,外层容器:focus-within统一承担辉光避免「双辉光」。示例里给该 select 加的.pvq-search__filter是语义钩子(自身无 CSS 规则),实际样式由后代选择器.pvq-search--with-filter .pvq-select提供;不写该钩子也能正常工作。 几何契约(v1.4.1 修正,勿再踩):筛选段是flex:none; width:110px的流内 flex 子项(不是绝对定位),故<input>(flex:1)自身左缘已在容器 110px 处。据此:图标用容器坐标left:124px(= 110 段宽 + 14 间隙);输入框padding-left必须用 input 自身坐标 取40px(= 150 − 110),文字才落在容器 150px(图标右缘 138 + 12 间隙)。切勿写成 150px —— 那会让文字落到 260px、比预期多出整整一个段宽(1.2.8 ~ 1.4.0 的缺陷即此)。 若将来要几何令牌化,正确形式是padding-left: calc( var(--pvq-search-text-x, 150px) - var(--pvq-search-filter-w, 110px) )—— 要减段宽,因为图标用容器坐标、padding 用元素自身坐标,两者坐标系不同;这一步属新增令牌 = MINOR,未纳入 1.4.1(PATCH)。--loading:图标位转 spinner(.pvq-search--loading .pvq-search__spinner显示);插件在异步检索期间自行加/去该类。--sm:紧凑高度 34px(图标/缩进同步缩小),用于表格工具条等密集区。
-
形状变体(新增 4 个):
--pill(全圆角,已有圆角语义)、--underline(无框仅底线,极简克制)、--ghost(填底无边框,聚焦加环)、--glass(半透明 +backdrop-filter: blur,前端装饰,需彩色背板才能看到 blur)。 -
暗色不是变体:暗色由库
--pvq-surface/--pvq-text/--pvq-border/--pvq-primary令牌主题切换,.pvq-search自动适配,不新增暗色修饰符。 -
JS(库自动初始化,
initSearches(),initAll自动调用,幂等):清除按钮显隐/清空;提交(按钮点击或回车,回车preventDefault)与筛选change(仅当有词)派发pvq-searchCustomEvent(bubbles,detail: { query, filter, element }),插件监听该事件执行真实检索(库不假设后端)。加载态由插件控制。 -
示例(默认 / 带按钮 / 形状 / 毛玻璃 / 筛选 / 小号+加载 / 蓝橙 accent):
<!-- 默认填框 + 清除 --> <div class="pvq-search" data-pvq-search> <i class="pvq-search__icon fas fa-magnifying-glass"></i> <input class="pvq-search__input" type="text" placeholder="搜索文章、用户、标签…"> <button class="pvq-search__clear" type="button" aria-label="清除"><i class="fas fa-xmark"></i></button> </div> <!-- 带提交按钮 --> <div class="pvq-search pvq-search--with-btn" data-pvq-search> <i class="pvq-search__icon fas fa-magnifying-glass"></i> <input class="pvq-search__input" type="text" placeholder="输入关键词后点搜索"> <button class="pvq-search__submit" type="button"><i class="fas fa-magnifying-glass"></i> 搜索</button> </div> <!-- 筛选前置(复用库 .pvq-select) --> <div class="pvq-search pvq-search--with-filter" data-pvq-search> <div class="pvq-select pvq-search__filter"> <select name="pvq_search_scope"> <option>全部</option><option>标题</option><option>正文</option><option>作者</option> </select> </div> <i class="pvq-search__icon fas fa-magnifying-glass"></i> <input class="pvq-search__input" type="text" placeholder="在所选范围内搜索…"> </div> <!-- 蓝/橙强调:仅覆盖令牌,形状不变 --> <div class="pvq-search pvq-search--with-btn" data-pvq-search style="--pvq-search-accent:#2563eb"> <i class="pvq-search__icon fas fa-magnifying-glass"></i> <input class="pvq-search__input" type="text" placeholder="蓝色主题搜索…"> <button class="pvq-search__submit" type="button"><i class="fas fa-magnifying-glass"></i> 搜索</button> </div> -
插件监听检索事件:
document.addEventListener('pvq-search', function (e) { var q = e.detail.query, scope = e.detail.filter; // 调用真实检索接口… });
颜色输入框 ColorField · experimental【新增】
- 结构:
.pvq-color-field>.pvq-color-field__swatch+input.pvq-color-field__input(CSS 选择器写成.pvq-color-field input.pvq-color-field__input以抬升特异度压过 WP 核心;HTML class 不变) - 行为:点击色块弹出全局共享自绘取色面板(饱和度/亮度 Canvas + 色相条 + hex 输入),圆头鼠标指示器;手动输入 hex 双向同步色块
- 取色面板通过
position: fixed挂<body>(全局唯一,所有 ColorField 共享),点击外部或按确定/Enter 关闭并应用 - 变体:
.pvq-color-field--sm(小号) - JS 入口:
window.PVQUI.initColorFields()(initAll()自动调用,仅建一次共享面板) - 示例:
<div class="pvq-color-field" data-pvq-color-field> <div class="pvq-color-field__swatch" data-hex="#608062" style="background:#608062"></div> <input type="text" class="pvq-color-field__input" value="#608062" maxlength="7"> </div>
转圈 Spinner · stable
- 类:
.pvq-spinner;动画@keyframes pvq-spin
元信息列表 Meta-list(原 system-info)· stable
- 类:
.pvq-meta-list.pvq-meta-list__row.pvq-meta-list__key.pvq-meta-list__value.pvq-meta-list__value--{ok,bad}.pvq-meta-list__value与.pvq-meta-list__key同排继承.pvq-meta-list的字号/颜色,自身无独立 CSS 规则(纯扩展钩子);着色由修饰符--ok(绿)/--bad(红)提供。 - 示例:
<div class="pvq-meta-list"> <div class="pvq-meta-list__row"><span class="pvq-meta-list__key">PHP</span><span class="pvq-meta-list__value pvq-meta-list__value--ok">8.1</span></div> </div>
动画 Animations · stable
@keyframes pvq-spin(转圈)、pvq-pulse(状态点)、pvq-shimmer(光泽)、pvq-slideDown/Up、pvq-cardEnter、pvq-tabEnter、pvq-iconBounce、pvq-badgePulse、pvq-resultSlide、pvq-logoAppear、pvq-lightbulb、pvq-detectBarEnter- base 层另含
@media (prefers-reduced-motion: reduce)全局降级。
3.2 Admin 层(pvq-ui-admin.css)
设置页骨架 Settings · stable
- 类:
.pvq-settings.pvq-settings__header.pvq-settings__logo.pvq-settings__title-group.pvq-settings__title.pvq-settings__subtitle.pvq-settings__version-badge.pvq-settings__footer.pvq-settings__footer-info.pvq-settings__footer-links.pvq-settings__footer-link.pvq-settings__footer-link--disabled
选项卡 + 磁吸滑块 Tabs · stable
- 类:
.pvq-tabs.pvq-tabs__slider.pvq-tab.pvq-tab--active.pvq-tab__icon.pvq-tab-content.pvq-tab-content--active - 交互:库 JS 委托点击切换 + 移动滑块(见《调用手册》§5)。
- 形态:分段控件式胶囊(pill)。容器
.pvq-tabs、磁吸滑块.pvq-tabs__slider、tab.pvq-tab均为全圆角(--pvq-radius-pill: 999px);容器width: fit-content紧凑跟随内容(不撑满整行)、1px--pvq-border-light淡边框(与pvq-wp一致);激活态靠滑块主色渐变垫底、文字白,未激活灰字、hover浅主色底。JS 仅按offsetLeft/offsetWidth定位滑块,圆角变化不影响逻辑。参考pvq-wp选项卡实现(1.1.1 起由矩形圆角改为胶囊,1.1.2 起边框对齐 pvq-wp 淡边框)。 - 示例:
<div class="pvq-tabs"> <span class="pvq-tabs__slider"></span> <button class="pvq-tab pvq-tab--active" data-pvq-tab="general"><i class="pvq-tab__icon fas fa-cog"></i> 常规</button> <button class="pvq-tab" data-pvq-tab="advanced"><i class="pvq-tab__icon fas fa-sliders-h"></i> 高级</button> </div> <div class="pvq-tab-content pvq-tab-content--active" data-pvq-tab-panel="general">…</div> <div class="pvq-tab-content" data-pvq-tab-panel="advanced">…</div>
范围 Range · stable(见 §3.1,admin 设置页常用,随 admin 层提供)
3.3 Editor 层(pvq-ui-editor.css)
块骨架 Block · stable
- 类:
.pvq-block-placeholder.pvq-block-loading.pvq-block-empty.pvq-block-preview.pvq-block-frame - 说明:通用块编辑占位 / 加载 / 空态 / 预览 / 边框,供各插件块复用。
3.4 Frontend 层(pvq-ui-frontend.css)
内容组件 · stable
- 类:
.pvq-callout.pvq-callout__icon.pvq-callout__content.pvq-quote.pvq-prose - 说明:前端通用内容展示(提示框 / 引用 / 正文排版)。
进度条 Progress · stable(1.2.9 并入)
- 类:
.pvq-progress.pvq-progress__fill.pvq-progress__text;变体.pvq-progress--lg(大号)、.pvq-progress--danger(危险红,走--pvq-danger)。 - 令牌:
--pvq-progress-accent(默认--pvq-primary绿,危险态覆盖为--pvq-danger),零硬编码。 - 纯 CSS,进度由 JS 设置
.pvq-progress__fill的width。 - 示例:
<div class="pvq-progress"><div class="pvq-progress__fill" style="width:35%"></div><span class="pvq-progress__text">35%</span></div> <div class="pvq-progress pvq-progress--danger"><div class="pvq-progress__fill" style="width:88%"></div><span class="pvq-progress__text">88% 风险</span></div>
书签 Bookmark · stable(1.2.9 并入)
- 类:
.pvq-bookmark.pvq-bookmark__image.pvq-bookmark__content.pvq-bookmark__url.pvq-bookmark__favicon.pvq-bookmark__title.pvq-bookmark__description - 结构:左图(
.pvq-bookmark__image)右文(url + 标题 + 描述);去掉__image即纯文字链接卡。hover 浅绿底 + 稍深边框(--pvq-border-strong)。 - 示例:
<a class="pvq-bookmark" href="https://pvq.ink"><div class="pvq-bookmark__image" style="background-image:url(...)"></div><div class="pvq-bookmark__content"><div class="pvq-bookmark__url"><img class="pvq-bookmark__favicon" src="...">pvq.ink</div><div class="pvq-bookmark__title">PVQ 组件库官网</div><div class="pvq-bookmark__description">统一全站界面样式的跨插件组件库。</div></div></a>
卡片化表格 Table · stable(1.2.9 并入)
- 类:
.pvq-table(配合.pvq-table-wrap可加[data-pvq-table]触发入场动画);子结构即原生table/thead/tbody/tr/th/td,可选caption。 - 默认观感:单元格独立圆角卡片、彼此留
0.3em间隙(border-collapse:separate);表头绿底(--pvq-table-head-bg)、单元格淡绿底(--pvq-table-cell-bg);悬停高亮 + 微放大(scale(1.01)+ 阴影)。 - 修饰符:
--striped(斑马纹,偶数行整行单元格换深一档绿底--pvq-table-stripe-bg);列级对齐__col--right/__col--center。整表对齐/边框/紧凑等变体在卡片语境下不成立(已不提供)。 - 令牌(定义在
.pvq-table,零硬编码):--pvq-table-radius/--pvq-table-head-bg/--pvq-table-head-bg-hover/--pvq-table-cell-bg/--pvq-table-cell-bg-hover/--pvq-table-stripe-bg,均派生自--pvq-primary/--pvq-radius-md。 - 入场动画:
.pvq-table-wrap[data-pvq-table]由库 JSinitTables()经 IntersectionObserver 触发(pvq-is-visible);普通.pvq-table不加data-pvq-table则完全可见、无入场。 - 示例:
<div class="pvq-table-wrap" data-pvq-table><table class="pvq-table"><caption>语言速览</caption><thead><tr><th>语言</th><th class="pvq-table__col--right">诞生年</th></tr></thead><tbody><tr><td>PHP</td><td class="pvq-table__col--right">1995</td></tr></tbody></table></div> <!-- 斑马纹:<table class="pvq-table pvq-table--striped"> -->
权重输入框 Weight · stable(v1.2.10 新增,随 1.2.11 固化发布)
- 类:
.pvq-weight.pvq-weight__list.pvq-weight__item.pvq-weight__label.pvq-weight__badge.pvq-weight__input-wrap.pvq-weight__input(数字input[type="number"],CSS 写input.pvq-weight__input,0,2,1 压过 WP 核心).pvq-weight__unit(单位%/后缀).pvq-weight__slider-wrap.pvq-weight__slider(滑块input[type="range"],CSS 写input.pvq-weight__slider,0,2,1).pvq-weight__action(底部操作区).pvq-weight__total(总和显示).pvq-weight__total-val。 - 用途:多维权重配置(功能 / 性能 / 美观…),数字输入框 + 滑块双向联动微调,底部「重置 / 归一化」按钮使总和归 100;总和实时显示。
- 设计原则:形状归库、颜色归令牌。组件定义
--pvq-weight-accent(默认var(--pvq-primary)绿),聚焦边框/辉光/滑块主色/单位底全走它;hover 用color-mix(in srgb, accent 45%, #fff)压浅,零硬编码。主按钮复用库.pvq-btn--primary(绿渐变 + hover),重置复用.pvq-btn--ghost,胶囊外形由.pvq-weight__btn-pill覆圆角(--pvq-radius-pill);组件本身不重定义按钮底色。 - 结构契约:
.pvq-weight__item由 3 段横向排列(label / input-wrap / slider-wrap),flex-wrap允许窄屏换行;.pvq-weight__input-wrap为position:relative,.pvq-weight__unit绝对定位右侧(数字框padding-right让位)。JS 负责双向同步(输入→滑块、滑块→输入)与总和/归一化/重置逻辑——纯展示外壳归库,归一化算法由调用方可覆盖(监听pvq-weight:normalize事件,或仅用默认window.PVQUI.initWeights())。 - 令牌:
--pvq-weight-accent(默认主色)、--pvq-weight-item-bg(卡片行底var(--pvq-surface-hover))、--pvq-weight-item-hover(hover 浅主色底),全部派生自--pvq-primary;不新增基础令牌(复用既有--pvq-border-strong/--pvq-primary-glow/--pvq-radius-pill)。 - 变体:
.pvq-weight--sm(紧凑行高)、.pvq-weight--glass(半透明 +backdrop-filter玻璃拟态,需彩色背板才显 blur)。 - JS 入口:
window.PVQUI.initWeights()(initAll()自动调用,幂等):扫描[data-pvq-weight],对每行数字框/滑块做双向同步 + 实时总和;绑定「归一化」「重置」按钮(按钮须带data-pvq-weight-normalize/data-pvq-weight-reset);归一化后派发pvq-weight:normalized事件供插件接后端持久化。 - 示例(最小结构):
<div class="pvq-weight" data-pvq-weight> <div class="pvq-weight__list"> <div class="pvq-weight__item"> <span class="pvq-weight__label">功能 <span class="pvq-weight__badge">w1</span></span> <div class="pvq-weight__input-wrap"> <input class="pvq-weight__input" type="number" min="0" max="999" step="0.1" value="35" aria-label="功能 权重"> <span class="pvq-weight__unit">%</span> </div> <div class="pvq-weight__slider-wrap"> <input class="pvq-weight__slider" type="range" min="0" max="100" step="0.5" value="35" aria-label="功能 滑块"> </div> </div> </div> <div class="pvq-weight__action"> <span class="pvq-weight__total">∑ 总和 <span class="pvq-weight__total-val">100.0</span></span> <div class="pvq-btn-group"> <button type="button" class="pvq-btn pvq-btn--ghost pvq-weight__btn-pill" data-pvq-weight-reset>↺ 重置</button> <button type="button" class="pvq-btn pvq-btn--primary pvq-weight__btn-pill" data-pvq-weight-normalize>⟳ 归一化</button> </div> </div> </div>
数据表格 DataGrid · stable(1.2.9 并入,含 JS 交互)
- 结构:
.pvq-datagrid[data-pvq-datagrid]>.pvq-datagrid__toolbar(搜索/排序/筛选/重置按钮)+.pvq-datagrid__content>.pvq-datagrid__table(同卡片化表格)+.pvq-datagrid__empty(无结果提示)。 - 工具栏:① 搜索
.pvq-datagrid__search(自包含胶囊:折叠为圆图标,点图标原地展开成输入框,点击栏外空白收起);② 排序.pvq-datagrid__btn--sort(点头列或按钮三态循环 无/升/降);③ 筛选.pvq-datagrid__filter(自包含胶囊:展开为「列 + 值」双自绘下拉多选,点击栏外空白收起);④ 重置.pvq-datagrid__btn--reset(旋转图标,清空搜索/筛选/排序)。 - 交互(库 JS
initDataGrids(),initAll自动调用,幂等):搜索实时过滤行、排序重排、筛选按列+值多选、重置恢复;入场动画同上([data-pvq-datagrid]触发)。 - 表头排序图标:
.pvq-sort-icon(升↑/ 降↓由.pvq-sort-asc/desc控制)。该载体由库 JS 在initSort时自动注入每个表头(缺失才补),标记中可省略;默认态显示中性上下箭头↕,悬停/升/降态高亮。隐藏行类.pvq-search-hidden/.pvq-filter-hidden。 - 尺寸/令牌:复用 Table 的
--pvq-table-*令牌;工具栏按钮.pvq-datagrid__btn圆角胶囊(白底--pvq-surface,hover 浅灰--pvq-surface-hover)。激活态.pvq-datagrid__btn--active绿底白字(--pvq-primary);:hover/:focus-visible必须用--pvq-primary-hover保持绿系(与全库主按钮 hover 一致)——否则.pvq-datagrid__btn:hover(特异性 0,1,1)的浅灰背景会盖掉--active绿底(0,1,0),激活态图标color:#fff落在浅灰底上不可见(视觉「白→白→黑」三态跳变)。v1.2.9 修正。** - 筛选下拉菜单由库 JS 依据表头(
th[data-col])与单元格值自动生成,无需手写<option>。 - 示例(最小结构):
<div class="pvq-datagrid" data-pvq-datagrid> <div class="pvq-datagrid__toolbar"> <div class="pvq-datagrid__search"><button class="pvq-datagrid__toggle pvq-datagrid__toggle--search" type="button"><i class="fas fa-magnifying-glass"></i></button><input class="pvq-datagrid__search-input" type="text" placeholder="搜索…"><button class="pvq-datagrid__search-clear" type="button"><i class="fas fa-xmark"></i></button></div> <button class="pvq-datagrid__btn pvq-datagrid__btn--sort" type="button"><i class="fa-solid fa-up-down"></i></button> <div class="pvq-datagrid__filter"><button class="pvq-datagrid__toggle pvq-datagrid__toggle--filter" type="button"><i class="fas fa-filter"></i></button><div class="pvq-dd" data-pvq-dd="col"><button class="pvq-dd__trigger" type="button"><span class="pvq-dd__text">选择列</span><i class="pvq-dd__arrow fas fa-chevron-down"></i></button><div class="pvq-dd__menu"></div></div><div class="pvq-dd" data-pvq-dd="val"><button class="pvq-dd__trigger" type="button"><span class="pvq-dd__text">选择值</span><i class="pvq-dd__arrow fas fa-chevron-down"></i></button><div class="pvq-dd__menu"></div></div></div> <button class="pvq-datagrid__btn pvq-datagrid__btn--reset" type="button"><i class="fas fa-rotate-left"></i></button> </div> <div class="pvq-datagrid__content"><table class="pvq-datagrid__table"><thead><tr><th data-col="项目">项目<i class="pvq-sort-icon"></i></th></tr></thead><tbody><tr><td>示例</td></tr></tbody></table><div class="pvq-datagrid__empty">无匹配结果</div></div> </div>
4. 不在库内(留在插件自有)
以下强绑定各自数据模型 / 业务逻辑,不进库,但要求改用 --pvq-* 令牌保持一致风格:
- wolai 专有:
.pvq-wolai-*、.pvq-token-info、.pvq-detect-bar、.pvq-status-available/-unavailable、.pvq-wolai-callout等。 - 各插件业务逻辑专有样式,留在插件,不回流库。
5. 新增组件流程(库增量贡献)
- 先查本表确认不存在。
- 在
doc/开发文档/或本表写组件条目(API / 类 / 令牌 / 示例),先标experimental。 - 写 CSS/JS(BEM 双横线、统一令牌、
pvq-动画前缀)。 - bump 版本(MINOR),按《PVQ-UI项目规则.md》§1.3 版本七处同步,并同步
CHANGELOG.md、readme.md与site/inc/components.json的version/stability。 - 经 1~2 个插件验证后,本表稳定性改为
stable。
详见《PVQ-UI项目规则.md》§1、§5、§8 与《库演进治理方案.md》§4。