PVQ-UI
v1.2.10
Gitee

文档

PVQ-UI 的开发方案、项目规则、组件清单与调用方法。文档为代码唯一真源,本页直接渲染仓库中的真实 Markdown。

开发方案

PVQ-UI 组件库开发方案

状态:草案(待评审定稿) 作者:溟远 适用仓库:pvq-ui(独立组件库) 关联插件:pvq-wolai-syncpvq-threads-sync(后续迁移);参考 pvq-wp 的 FontAwesome 统一管理模式


1. 背景与目标

1.1 真实需求(一句话)

写一次组件库,以后写插件直接调用它,不再单独写组件;存量插件逐步替换成它,实现全站样式统一。

1.2 当前痛点(已核实代码)

  • pvq-wolai-sync 后台已实现一套完整的 .pvq-* 通用组件 + 全套 --pvq-* 设计令牌(assets/css/admin-settings.css:11-62)。
  • pvq-threads-sync 另起一套 .pvq-ts-* 命名空间,并*复制了同一套 `--pvq-令牌**(assets/css/admin.css:8-43),连 FontAwesome 都硬编码了自己的 handle(includes/class-threads-sync.php:234threads-sync-fa`)。
  • 结果:同一套设计语言被重复实现、各自演进,风格必然漂移,且每次新插件都要重写一遍通用组件。

1.3 目标

  1. pvq-ui 成为所有 PVQ 插件的「界面样式唯一真源」。
  2. 新插件从第一天起直接调用 pvq-ui,零通用组件副本。
  3. 存量插件(wolai → threads)分阶段替换,统一视觉语言。
  4. 设计令牌(颜色 / 圆角 / 阴影 / 动画)全站一致。

2. 设计原则(精简版,已修正草案矛盾)

  1. 单一真源:通用组件只存在于 pvq-ui,插件不再自带副本。
  2. CDN 单一源:构建产物上传固定 URL,所有插件引用同一 URL(零本地副本、零 build 同步)。
  3. 自给自足:不依赖 pvq-wp,也不强制安装任何基座插件。收敛逻辑随库自带(见 §3.3),而非各插件重写。
  4. BEM 命名pvq-{block} / pvq-{block}__{element} / pvq-{block}--{modifier}
  5. 渐进完善:先落地最高频的后台设置页 + 通用组件,前端 / 编辑器组件随后补充。

修正说明:原草案 §2.3「纯自给自足」与 §3.3「每个消费插件挂载 override 收敛」自相矛盾——若每个插件各自重写收敛逻辑,既不单一真源又易出 bug。本方案改为:收敛逻辑内置于库自带的 pvq-ui-loader.php 单一文件,由各插件复制引用,而非重写(见 §3.3)。


3. 架构与运行机制

3.1 产物(CDN 固定路径)

构建后上传到 https://<CDN_BASE>/pvq-ui/<版本>/ 下的固定文件名:

文件 场景 WordPress handle 依赖
pvq-ui.css 全场景 base(令牌 + 通用组件) pvq-ui
pvq-ui-admin.css 后台 pvq-ui-admin pvq-ui, font-awesome
pvq-ui-editor.css 块编辑器 pvq-ui-editor pvq-ui
pvq-ui-frontend.css 前端 pvq-ui-frontend pvq-ui
pvq-ui.js 全场景交互(原生 JS) pvq-ui

组件视觉大量使用 FontAwesome 图标(按钮 / 卡片图标 / 连接状态等),故 pvq-ui-admin 必须声明对 font-awesome 句柄的依赖;loader 会一并保证 FA 已注册(见 §3.3)。

3.2 常量 + 句柄守卫(平移 FontAwesome 模式)

先定义者生效、同句柄不重复注册:

if ( ! defined( 'PVQ_UI_URL' ) )      define( 'PVQ_UI_URL',      'https://<CDN_BASE>/pvq-ui/<ver>/pvq-ui.css' );
if ( ! defined( 'PVQ_UI_ADMIN_URL' ) )define( 'PVQ_UI_ADMIN_URL','https://<CDN_BASE>/pvq-ui/<ver>/pvq-ui-admin.css' );
if ( ! defined( 'PVQ_UI_EDITOR_URL' ) )define('PVQ_UI_EDITOR_URL','https://<CDN_BASE>/pvq-ui/<ver>/pvq-ui-editor.css' );
if ( ! defined( 'PVQ_UI_FRONT_URL' ) )define( 'PVQ_UI_FRONT_URL','https://<CDN_BASE>/pvq-ui/<ver>/pvq-ui-frontend.css' );
if ( ! defined( 'PVQ_UI_VERSION' ) )  define( 'PVQ_UI_VERSION',  '1.0.0' );

foreach ( array( 'pvq-ui' => PVQ_UI_URL, 'pvq-ui-admin' => PVQ_UI_ADMIN_URL, 'pvq-ui-editor' => PVQ_UI_EDITOR_URL, 'pvq-ui-frontend' => PVQ_UI_FRONT_URL ) as $h => $url ) {
    if ( ! wp_style_is( $h, 'registered' ) ) {
        $deps = ( 'pvq-ui' === $h ) ? array() : array( 'pvq-ui' );
        if ( 'pvq-ui-admin' === $h ) $deps[] = 'font-awesome';
        wp_register_style( $h, $url, $deps, PVQ_UI_VERSION );
    }
}

3.3 pvq-ui-loader.php(单一收敛点,随库分发)

库随附一个自包含pvq-ui-loader.php(约 60 行)。消费方复制到自身 includes/require_once 并调用助手函数即可:

require_once __DIR__ . '/pvq-ui-loader.php';
PVQ_UI_Loader::enqueue( array( 'admin' ) ); // 后台场景;'editor' / 'frontend' 同理

该文件集中负责:

  1. 定义 §3.2 的 4 个常量(均 defined() 守卫);
  2. 注册 4 个句柄(wp_style_is 守卫);
  3. 提供 PVQ_UI_Loader::enqueue( $scenes ) 助手;
  4. 版本收敛(override)内置于此,挂载 wp_print_styles(999),把所有 pvq-ui* 句柄的 src/ver 收敛到对应常量 URL,防止某插件硬编码旧版。

收敛逻辑用 did_action('pvq_ui_override_registered') 守卫,多副本只实际挂载一次、幂等;默认开启,可被常量 PVQ_UI_NO_CONVERGE 关闭。

这样「自给自足」与「统一收敛」不再矛盾:单一真源是库文件,不是各插件重写;且不依赖 pvq-wp

3.4 句柄 / 常量集中

全部常量在 pvq-ui-loader.php 顶部集中定义;消费方只通过 defined() 保护做覆盖(便于内网站点把 URL 指向本地副本)。

3.5 组件清单 JSON 唯一真源 + 官网画廊数据驱动

组件清单长期存在两份漂移隐患:①doc/模块文档/设计令牌与组件清单.md(人类可读);②site/inc/gallery.php(官网画廊手抄 HTML)。本方案收敛为单一机器可读真源 site/inc/components.json

  • 结构{ "version", "groups":[ { "title", "items":[ { "id","name","icon","stability","layer","desc","demos":[ { "title","html" } ] } ] } ] }demos[].html 即画廊"预览"与"代码示例"共用的同一份 HTML——只写一次,预览和代码块都从它来。
  • 官网画廊数据驱动gallery.php 遍历 JSON 自动生成侧边栏导航、每个组件的 <section> 预览区与代码块。新增组件只需在 JSON 的 items 加一条,画廊侧边栏 + 预览 + 代码全部自动出现,杜绝手抄三遍。
  • 双轨部署(本地即时 + 线上跟版本)
    • 本地:gallery.php 直接读仓库内 site/inc/components.json,改 JSON 刷新即见(无需部署)。
    • 线上:deploy.shcomponents.json 一并同步到 COS pvq-ui/v{ver}/components.jsongallery.php 运行时读该同版本 JSON(与库 CSS 同目录同版本,天然一致)。
  • .md 的关系.md 降级为"人类可读 API 说明",引用 JSON 条目、不再手抄示例;令牌表(:root 全集)仍留 .md(令牌不进 JSON)。凡"有无某组件"以 JSON 为准。

该 JSON 随库版本一起发布到 COS,库一升级,线上画廊自动跟随多组件、变稳定性标签。


4. 文件结构与组件清单

标注 [提取] = 直接来自现有 pvq-wolai-sync/assets/css/admin-settings.css[新增] = 库首次提供。

4.1 pvq-ui.css(base,全场景 enqueue)

  • 设计令牌:root 全套 --pvq-*(以 wolai admin-settings.css:11-62:root 为基线,原样保留命名)。
  • 按钮 [提取].pvq-btn .pvq-btn--primary .pvq-btn--secondary .pvq-btn--danger .pvq-btn--warning .pvq-btn-group
  • 卡片 [提取].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
  • 表单 [提取].pvq-field .pvq-field__label .pvq-field__help .pvq-input .pvq-input__wrap .pvq-input__wrap--has-icon .pvq-input__icon .pvq-input__toggle
  • 开关 [提取].pvq-switch .pvq-switch--active .pvq-switch-row .pvq-switch-row__label .pvq-switch-row__desc
  • 状态/徽标 [提取+新增].pvq-status .pvq-status--{success,warning,error} .pvq-status__dot .pvq-badge [新增]
  • 其它 [提取].pvq-divider .pvq-spinner .pvq-help .pvq-help__icon .pvq-help__title .pvq-help__text .pvq-banner .pvq-banner--{success,danger,warning,info} .pvq-alert .pvq-alert--{success,error,loading} .pvq-stat-grid .pvq-stat .pvq-stat__value .pvq-stat__label .pvq-meta-list .pvq-meta-list__row .pvq-meta-list__key .pvq-meta-list__value .pvq-meta-list__value--{ok,bad} [新增 meta-list]
  • 动画:全部 @keyframes 保留 pvq- 前缀(含 .pvq-spin/.pvq-pulse/.pvq-shimmer 等现有动画)。

4.2 pvq-ui-admin.css(后台 enqueue)

  • 设置页骨架 [提取].pvq-settings .pvq-settings__{header,logo,title-group,title,subtitle,version-badge,footer,footer-info,footer-links,footer-link,footer-link--disabled}
  • 选项卡 + 磁吸滑块 [提取].pvq-tabs .pvq-tabs__slider .pvq-tab .pvq-tab--active .pvq-tab__icon .pvq-tab-content .pvq-tab-content--active
  • 滑块 + 数字 [提取].pvq-range .pvq-range__group .pvq-range__value .pvq-range__labels
  • 系统信息 [提取].pvq-meta-list(见 4.1)

4.3 pvq-ui-editor.css(块编辑器 enqueue)

  • 通用块骨架 [提取自 wolai 专有抽象].pvq-block-placeholder .pvq-block-loading .pvq-block-empty .pvq-block-preview .pvq-block-frame

4.4 pvq-ui-frontend.css(前端 enqueue)

  • 通用内容组件 [提取自 wolai 专有抽象].pvq-callout .pvq-callout__{icon,content} .pvq-quote .pvq-prose

不进库、留在 wolai-sync 的强绑定笔记数据模型的样式:.pvq-wolai-text / -heading / -code-block / -todo / -toggle / -image / -video / -bookmark / -table 等,但改用 --pvq-* 令牌保证风格一致。.pvq-token-info.pvq-detect-bar.pvq-status-available/-unavailable 等 wolai 专有类也留在 wolai。


5. 设计令牌(节选,命名保持不变)

主色 --pvq-primary 系列、语义色 --pvq-{success,danger,warning,info}-light、中性色 --pvq-{bg,surface,border,text,text-secondary,text-muted}、圆角 --pvq-radius{,-sm,-lg}、阴影 --pvq-shadow{,-sm,-md,-lg,-primary}、缓动 --pvq-ease*--pvq-transition*。完整清单以 wolai admin-settings.css:11-62 为基线,由库统一维护。


6. BEM 命名规范与旧→新映射(修正版)

重要:旧类多为双类组合(如 pvq-btn pvq-btn-primary),并非单类,迁移时勿当单类搜索替换。完整映射表写入本文档附录,供迁移对照。

旧(真实代码) 新(pvq-ui BEM) 备注
pvq-btn + pvq-btn-primary pvq-btn + pvq-btn--primary 双类
pvq-btn-secondary / pvq-btn-danger / pvq-btn-warning pvq-btn--secondary / pvq-btn--danger / pvq-btn--warning
pvq-card-icon + primary pvq-card__icon + pvq-card__icon--primary 双类
pvq-label pvq-field__label
pvq-field-help pvq-field__help 草案误写为 .pvq-label-hint
pvq-input-wrap + has-icon pvq-input__wrap + pvq-input__wrap--has-icon 双类
pvq-switch + active pvq-switch + pvq-switch--active 双类
pvq-switch-label / pvq-switch-desc pvq-switch-row__label / pvq-switch-row__desc
pvq-status-indicator + success/warning/error pvq-status + pvq-status--success/warning/error
pvq-connection-status + connected/disconnected/unconfigured pvq-banner + pvq-banner--success/danger/warning 修饰符值需变更
pvq-test-result + .show + .success/.error/.loading pvq-alert + 显隐类 + pvq-alert--success/error/loading 需新增显隐类
pvq-cache-stats / pvq-cache-stat / pvq-cache-stat-value / pvq-cache-stat-label pvq-stat-grid / pvq-stat / pvq-stat__value / pvq-stat__label 中间层 pvq-cache-stat 勿漏
pvq-help-card (+ -inner / -icon / -title / -text) pvq-help (+ __icon / __title / __text)
pvq-settings-app / pvq-settings-header / pvq-settings-logo / pvq-settings-title / pvq-settings-subtitle / pvq-settings-footer / pvq-footer-link / pvq-footer-link--disabled pvq-settings / pvq-settings__header / __logo / __title / __subtitle / __footer / __footer-link / __footer-link--disabled
pvq-tab-slider / pvq-tab + active / pvq-tab-content + active pvq-tabs__slider / pvq-tab + pvq-tab--active / pvq-tab-content + pvq-tab-content--active 双类
pvq-range-group / pvq-range / pvq-range-value / pvq-range-labels pvq-range__group / pvq-range / pvq-range__value / pvq-range__labels
pvq-system-info / pvq-system-info-row pvq-meta-list / pvq-meta-list__row
pvq-wolai-callout (+ -icon / -content) pvq-callout (+ __icon / __content) 进 frontend
pvq-wolai-sync-placeholder pvq-block-placeholder 进 editor

7. JS 交互(pvq-ui.js,原生 JS + 事件委托)

  • tab 切换 + 磁吸滑块:委托 .pvq-tab 点击 → 切 .pvq-tab--active + .pvq-tab-content--active + 移动 .pvq-tabs__slider
  • switch 开关:委托 .pvq-switch 点击切 .pvq-switch--active,并 dispatchEvent 自定义事件 pvq-switch:change(detail 含 checked / data-target),插件监听后自行同步隐藏域与提交
  • range 拖动:同步 .pvq-range__value

迁移关键(草案低估的部分):现状 wolai 后台用 jQuery + 大量 inline onclick="pvqWolaiSwitchTab('general')" / onkeydown=...class-pvq-wolai-sync-settings.php:104,275,490)。迁移到 pvq-ui.js 必须剥离所有 inline handler,改为 data-* 属性 + 委托监听;switch 的「视觉 toggle」与「表单值同步」要重新划边界(库管视觉 + 派发事件,插件管隐藏域)。否则迁移后 JS 报错。


8. 消费方接入(PHP 样板 = 复制 loader + 一行调用)

// 每个插件只需:复制 pvq-ui-loader.php 到 includes/,然后:
require_once __DIR__ . '/pvq-ui-loader.php';
PVQ_UI_Loader::enqueue( array( 'admin' ) ); // 后台场景

// 插件自身 CSS:声明依赖 pvq-ui / pvq-ui-<场景>
wp_enqueue_style( 'my-plugin-admin', ..., array( 'pvq-ui', 'pvq-ui-admin' ), $ver );

相比原草案 §8:不再要求每个插件内联重复注册与 override 逻辑,全部收敛进 pvq-ui-loader.php


9. 迁移步骤(以 wolai-sync 先行)

  1. pvq-ui 仓库完成 base / admin / editor / frontend + pvq-ui.js + pvq-ui-loader.php,构建上传 CDN 固定路径。
  2. wolai 三个 enqueue 点(settings admin / frontend / editor)改为复制 pvq-ui-loader.php 并调用 PVQ_UI_Loader::enqueue();自身 CSS 加 pvq-ui / pvq-ui-admin 依赖。
  3. 删除 admin-settings.css 中已进库的通用组件 + :root 令牌;保留 wolai 专有类(.pvq-token-info.pvq-wolai-* 等)。
  4. 设置页 HTML/PHP 旧 class 全量改新 BEM 名(对照 §6 映射表);并剥离所有 inline onclick/onkeydown(§7)。
  5. frontend.css / editor.css 中 wolai 专有 .pvq-wolai-* 保留,硬编码颜色改为 --pvq-* 令牌;callout / 块骨架等抽象部分移交 pvq-ui
  6. 迁移完整性校验:grep 确认已进库的类(如 .pvq-card.pvq-btn--primary)在 wolai 自有 CSS/HTML 中零残留,避免与库双定义冲突。
  7. 同步 docs / readme.md / CHANGELOG(版本号三处同步)。
  8. threads-sync 后续按同流程迁移(注意其 .pvq-ts-* 命名空间需整体重命名为 .pvq-*)。

10. 新插件接入清单

  1. 复制 pvq-ui-loader.php 到插件 includes/
  2. 调用 PVQ_UI_Loader::enqueue( array( 'admin' / 'editor' / 'frontend' ) )
  3. 自身 CSS wp_enqueue_style(..., ['pvq-ui','pvq-ui-<场景>'])
  4. 只写插件专有样式,通用组件直接用 .pvq-* BEM 类。
  5. 不自带任何通用组件副本(纯 CDN 引用;内网站点可常量覆盖为本地副本)。

11. 风险与权衡

  • CDN 单点:UI(含 JS 交互)CDN 挂 → 设置页布局/交互崩。缓解:复用已在用域名 cdn-buke.pvq.ink;JS 交互保留 CSS 兜底(无 JS 也能看);内网站点用 PVQ_UI_URL 常量覆盖为本地副本。
  • 版本冲突:靠 §3.3 loader 内置 override 收敛(幂等),确保全站同一版本。
  • FA 依赖:组件视觉依赖 FontAwesome,loader 一并保证 font-awesome 句柄已注册。
  • 重命名成本:BEM 重命名需批量改所有插件 DOM 引用 + 文档/演示 HTML 硬编码类;一次性工程,靠 §6 映射表 + §9 第 6 步 grep 校验降低出错率。
  • 命名空间残留:wolai 后台通用类现用 .pvq-* 前缀,迁移须确保彻底删除,否则与库双定义。

12. 文档同步(铁律)

本方案定稿后写入 doc/开发文档/PVQ-UI组件库开发方案.md(即本文件,作为唯一真源)。 后续:

  • pvq-ui 仓库内维护 doc/模块文档/设计令牌与组件清单.md(令牌 + 组件 API)。
  • 更新现有文档(如 数据库块编辑器工具栏和FontAwesome方案.md、各插件 readme.md / CHANGELOG)。
  • 迁移盲区提醒docs/演示/*.html 中大量硬编码旧 handle / CDN / 设置项,须随迁移一并更新。
  • 遵循项目铁律:先文档 → 再代码 → 最后同步 CHANGELOG 与 readme(除非用户要求不更新版本号)。

13. 关联文档(单一真源拆分)

本方案为总纲,下列文档与之互为引用、共同构成唯一真源:

  • 组件提取对照表.md:三套现有组件(wolai / pvq-wp / threads)→ 库单一实现的逐组件映射与择优;迁移实施直接对照。
  • 库演进治理方案.md:库如何随插件开发持续演进——版本化 CDN、文档驱动增量贡献、组件分级(stable/experimental)、分层文件、防回潮。
  • PVQ-UI项目规则.md最高优先级权威规则,收敛散落各处的铁律(文档/单一真源/命名/版本化/分级/分层/接入/纪律);凡与本文冲突以它为准。
  • PVQ-UI组件库调用手册.md:插件开发者实操指南——复制 loader、一行 enqueue、直接写 .pvq-* 类、场景对照、常用组件速查、内网覆盖、迁移步骤、自检清单。

版本化细化:§3.1 的 CDN 路径已含 <版本>,各插件通过 PVQ_UI_Loader::enqueue( $scenes, $version ) 锁定版本;§11 的 override 收敛默认只解决"同版本冲突",不强制跨版本降级——从而支持"存量不动、新插件用最新"的渐进统一,匹配"随开发慢慢完善"的诉求。