PVQ-UI
v1.4.3
Gitee

文档

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

项目规则

PVQ-UI 项目规则(单一权威版)

状态:规范(最高优先级,覆盖各文档中零散的同类表述) 适用:所有 pvq-ui 仓库的修改、以及任何消费 pvq-ui 的 PVQ 插件 关联:《PVQ-UI组件库开发方案.md》(架构总纲)、《组件提取对照表.md》(实施映射)、《库演进治理方案.md》(持续运营)、《PVQ-UI组件库调用手册.md》(插件实操)


0. 这份文档的地位

本仓库此前散落多处"铁律"(总纲 §12、演进方案 §9、Agent 记忆中的项目铁律等)。此文档是这些规则的收敛点:凡与本文冲突,以本文为准。

任何人对本仓库动手前,先读本文 + 调用手册。


1. 文档铁律(最高优先级)

来源:项目级铁律 + 总纲 §12 + 演进 §9

  1. 先文档 → 再代码 → 最后同步版本号。任何功能新增 / 修复 / 调整,都要先更新 doc/开发文档/(或 doc/模块文档/),再根据文档改代码,最后同步 CHANGELOG.md 与 readme.md。
  2. 文档是唯一真源(Single Source of Truth):代码必须服从文档,文档也要反映代码。两者长期不一致视为缺陷。
  3. 版本七处同步:一次升版必须同时改齐 7 个版本标记,缺一即视为不一致缺陷: ① 仓库根 pvq-ui-loader.php 的 DEFAULT_VERSION(各插件 cp 复制的真源,漏改则调用方不传版本时拉旧产物); ② site/pvq-ui-loader.php 的 DEFAULT_VERSION; ③ assets/css/pvq-ui.css 的 @version; ④ assets/js/pvq-ui.js 的 @version; ⑤ site/inc/config.php 的 PVQ_UI_VERSION; ⑥ site/inc/components.json 的 version; ⑦ readme.md 当前版本与示例代码。 另须新增 CHANGELOG.md 版本块、同步本模块文档 §1 的当前库版本说明与组件稳定性标记。

    注:assets/css/pvq-ui-{admin,editor,frontend}.css 头部的 @version 是各层独立版本号,不随发布版本走,不在此七处之列。

  4. 用户豁免:用户明确要求"不更新版本号"时,第 3 条可暂缓,但第 1、2 条仍生效。

2. 单一真源与防回潮规则

来源:总纲 §2 + 演进 §8

  1. 通用组件只存在于 pvq-ui。插件不得自带通用组件副本(按钮 / 卡片 / 输入 / 开关 / 选项卡 / 横幅 / 统计 / 帮助 / 范围 / 分隔 / 转圈 / 状态指示等)。
  2. 已进库的类在插件自有代码中零残留定义。迁移 / 改造后必须 grep 校验:如 .pvq-card、.pvq-btn--primary 等在插件 CSS/HTML 中不得再被 @规则 定义(只可引用)。
  3. 组件清单唯一真源(JSON):site/inc/components.json 是库全部组件的机器可读唯一真源(组件 id / 名称 / 层 / 稳定性 / 附加说明 / 示例 HTML;字段语义见《组件库开发方案》§3.5——stability 严格二值 stable/experimental,layer 须与 CSS 实际所在层一致,来源与版本写进 note)。官网画廊(site/inc/gallery.php)数据驱动,遍历该 JSON 自动生成侧边栏与预览——新增组件只需在 JSON 加一条,画廊自动出现,杜绝手抄三遍漂移。模块文档 doc/模块文档/设计令牌与组件清单.md 是同一清单的人类可读 API 说明,引用 JSON、不再手抄示例;判断"某组件是否已存在"以 JSON 为准。
  4. 令牌只加不删:新增 --pvq-* 令牌追加即可;语义变更 / 删除只发生在 MAJOR 版本,且须在 CHANGELOG + 文档说明迁移路径。

3. 命名与编码规则

来源:总纲 §2.4 + §6、提取对照表 §3

  1. BEM 双横线:pvq-{block} / pvq-{block}__{element} / pvq-{block}--{modifier}。禁止单横线修饰符(如 .pvq-wp-btn-primary)。

    受控例外(1.4.0 明文登记):勾选框 / 单选的变体写作 .pvq-cb-variant-{strike,ghost,ripple}、.pvq-rb-variant-{card,ghost,ripple,solid},即以「变体名」作 block 而非 --modifier。这是既成事实(CSS / 组件清单 JSON / 文档三处一致),登记为受控例外而非改写——真 BEM 化(如 .pvq-cb--strike)属破坏性改名,须留待 MAJOR 并附迁移说明。新增组件不得再引入此类命名。

  2. *类前缀统一 `.pvq-**:禁止.pvq-wp-、.pvq-ts-` 等插件专属前缀污染库。
  3. @keyframes 统一 pvq- 前缀(如 pvq-spin / pvq-pulse),禁止 pvqWp* / pvq-ts* 等。
  4. 设计令牌优先:组件中颜色 / 圆角 / 阴影 / 动画一律用 --pvq-* 变量,禁止硬编码色值(内网站点主题 override 时再覆盖变量)。落地细则(1.4.0 明确):
    • 字面值只允许出现在令牌定义处(:root 或组件自身的作用域令牌声明,如 .pvq-table { --pvq-table-head-bg: … });组件规则体内一律引用 var(--pvq-*)。
    • 语义色的深浅派生用 color-mix(),不要写第二份 rgba:例如 12% 的危险色边框写 color-mix(in srgb, var(--pvq-danger) 12%, transparent),而非 rgba(196,84,84,0.12)。这样改 --pvq-danger 时派生色自动跟随(color-mix 与等价 rgba 在 sRGB 下逐位相同,属同值迁移)。
    • 受控例外(允许的字面值):无色相的中性叠加/遮挡——#fff / #000 及其半透明形式(按钮涟漪、遮罩、color-mix(..., #fff/#000) 的混合端点、取色器色相条)。它们不随主题色变化,写死不影响换肤。
    • 受控例外(防御性兜底):var(--pvq-token, fallback) 的兜底值允许保留,用于 base 层缺席时降级;兜底值必须与令牌定义一致,且不得依赖它生效(base 是各层依赖,正常都应命中令牌)。
  5. 库不假设主题变量存在:库是纯令牌提供方;pvq-wp 激活主题时的 --pvq-theme-* 映射由它自行在作用域 override。
  6. JS 交互原生 + 事件委托:pvq-ui.js 用原生 JS、委托监听,禁止 jQuery 依赖、禁止 inline onclick / onkeydown;库只管"视觉 + 派发事件",表单值同步等交给插件监听后处理。
  7. 页面生命周期事件纪律(v1.4.3 新增):
    • 禁用 unload:Chrome 已将 unload 纳入 Permissions Policy 并逐步默认禁用——策略不允许时注册监听即报 [Violation] Permissions policy violation: unload is not allowed in this document 且回调不执行;更早就存在的代价是:只要注册了 unload,页面即失去 bfcache 资格(后退变整页重载)。库内一律不得出现 unload / beforeunload。
    • 替代写法:释放类兜底用 pagehide(正常卸载与进入 bfcache 均触发,且不阻塞 bfcache);需要在"后退/前进恢复"时复位状态的用 pageshow + if (e.persisted)。
    • 状态残留必须可自愈:凡是需要成对释放的全局副作用(滚动锁、body / <html> 上的类与内联样式、计数器),都要能在 pageshow(persisted) 时被强制复位,否则 bfcache 恢复后会出现"整页滚不动"这类只在用户侧偶发的故障。
    • *禁止写 `document.body.style.做状态标记**(既有类约定:.pvq-scroll-locked`):内联样式会覆盖主题/消费方对同一属性的设置,且一旦漏恢复就再也发现不了;类开关幂等,任何时刻移除一次即完全释放。

4. 版本化规则(支持"随开发慢慢完善")

来源:演进 §3

  1. 语义化版本:MAJOR.MINOR.PATCH
    • PATCH:修样式 bug / 微调,不破坏类名。
    • MINOR:新增组件 / 新增修饰符 / 新增令牌(向后兼容,只加不删)。
    • MAJOR:破坏性改名 / 删类 / 改令牌语义(须文档说明迁移)。
  2. CDN 路径含版本:CSS 四层在 https://<CDN_BASE>/pvq-ui/v{MAJOR.MINOR.PATCH}/css/pvq-ui.css(及 -admin/-editor/-frontend),JS 在 .../js/pvq-ui.js,组件清单在 .../v{ver}/components.json。不提供 latest 别名:CDN 响应 Cache-Control: immutable, max-age=31536000,别名目录一旦被覆盖就会重演"浏览器一年内取旧缓存"的事故,且与"插件显式锁版本"纪律冲突;要试用新版就显式指向该版本号。
  3. 版本在全站只定义一处(v1.4.0 起,推荐):规定 站点级在 wp-config.php 定义一次 PVQ_UI_VERSION,插件调用 PVQ_UI_Loader::enqueue( $scenes ) 不传版本。 必须分清的两层「先到先得」(v1.4.2 明确;此前文档只写了第一层,导致漏判——见下):
    • 常量层:PVQ_UI_VERSION(defined() 守卫)→ 由第一个调用 enqueue() 者传入的版本决定。
    • 类层(更隐蔽):类定义被 if ( ! class_exists( 'PVQ_UI_Loader' ) ) 包裹 → 由第一个 require loader 的插件的副本赢得类归属;其后所有副本的 class_exists() 为真,整份文件被跳过,它们的 DEFAULT_VERSION / register() / converge() 从未执行。而所有调用点都"不传版本"、看起来完全合规,从现象根本看不出是版本问题(实测:旧副本先加载时,新版插件复制的 loader 被静默忽略,全站停在旧版,Popover/Toast 等新组件"不存在")。
    • ⇒ 只有站点常量能同时钉死两层。未定义常量时,全站版本实际由「最先加载的那份副本」决定。
    • v1.4.2 加固(针对未定义常量的兜底):每份副本在文件作用域(class_exists 守卫之外,故必然执行——这是混合版本副本共存时唯一可靠的感知通道)登记「本副本自述版本」与「本副本的类未生效」事实;随后:
      1. 无站点常量时:就地按各副本自述版本的最高者定义 PVQ_UI_VERSION。因为这一步在文件作用域完成,即便"最先加载的旧副本"赢得了类归属,其 register() 也会沿用它——加固不依赖"赢得类的是不是新版"(这是关键:若把加固只写在类方法里,旧副本赢得类时执行的仍是旧代码,加固等于没有)。
      2. 告警判据(只在真的被拉低时出声,健康站点零噪音):站点生效版本 < 最高副本版本 → _doing_it_wrong() + error_log 一次性告警,列出各副本版本、落后项、未生效副本与修复命令。
      3. 纯「副本之间有差异但未影响生效版本」不在运行时告警,交由 scripts/check-loader-copies.php 报阻塞项(开发期发现)。 站点常量已定义且不低于最高副本版本时行为完全不变、零输出。
    • 好处:版本单点、与加载顺序无关;也避免"某插件硬编码旧版把全站拉回去"(这正是 converge() 想解决但靠自身解决不了的问题)。
    • 例外(临时隔离才用):需某插件单独锁版本时才在调用处显式传版本;因先到先得语义,多插件长期共存多版本不可靠,不作为常规手段(v1.4.2 起该显式版本仍被尊重,但会触发上述告警)。
    • 存量不强制降级:站点常量一旦统一,全站同步到该版本即为"渐进统一"的终点。
  4. 插件 loader 副本必须同步(复制分发的代价):pvq-ui-loader.php 每插件 cp 一份,故库升版或 loader 逻辑改动后,插件侧副本会过期(版本号过期只在"该插件是第一个调用者且不传版本"时才有害;逻辑过期则一律有害)。纪律:
    • 升版后跑 php scripts/check-loader-copies.php 体检(只读、发现漂移非 0 退出;站点未定义 PVQ_UI_VERSION 也算阻塞项);
    • 需要修时跑 php scripts/sync-loaders.php --apply(默认干跑;留 .bak、逐个 php -l);
    • 判定规则:与真源逐字节一致→跳过;仅注释/DEFAULT_VERSION 差异→真源 cp 覆盖;衍生副本(自有文档头、if (...): 语法等)→最小侵入只改版本行及其行前注释。
    • .bak 约定:同步脚本写前留 .bak(便于即时回退),验证通过后应清除(find <插件目录> -name '*.bak*' -delete);.bak 不入库、不长期堆积。
    • ⚠️ 找副本必须跟随符号链接:本机多个插件是以符号链接安装的(wp-content/plugins/pvq-weixinyuedu -> /home/muyu/pvq-weixinyuedu、pvq-workfolio -> /mnt/c/Users/muyu/Documents/code/Gastronomy/wordpress/pvq-workfolio)。默认 find 不跟随符号链接,会整份漏掉这类插件的副本——这正是 2026-09-19 那份 1.2.10 陈旧副本长期未被发现的原因。因此:find **-L** /www/wwwroot/wordpress/wp-content /home/muyu -maxdepth 8 -name 'pvq-ui-loader.php';体检脚本已改为直接遍历插件目录并 realpath() 解析,不依赖 find。
    • 全站副本清单(2026-09-19 二次核实,共 4 份):① /home/muyu/pvq-weixinyuedu/includes/(安装处为软链;该目录非 git 仓库);② /www/wwwroot/wordpress/wp-content/plugins/pvq-wp/includes/;③ /www/wwwroot/wordpress/wp-content/plugins/pvq-threads-sync/includes/(衍生副本:自有文档头 + 冒号语法,已核实依赖逻辑与真源一致);④ /mnt/c/Users/muyu/Documents/code/Gastronomy/wordpress/pvq-workfolio/includes/(安装处为软链;独立 git 仓库 oh-af/pvq-workfolio;1.4.2 前为 1.2.10 陈旧副本且缺 1.2.9 的 font-awesome-frontend 逻辑)。① ② 与真源逐字节一致、③ 按纪律只改版本行、④ 因头部是标准头(非本地衍生)按整份 cp 覆盖。库自身 site/pvq-ui-loader.php 也必须与真源逐字节一致。新增插件后重跑体检,看是否多出第 5 份。
  5. override 收敛幂等:loader 内置收敛只解决"同版本冲突",多次挂载幂等;默认开启,可被 PVQ_UI_NO_CONVERGE 关闭。

5. 组件分级规则

来源:演进 §5

  1. stable:成熟、承诺不破坏性改(仅可加修饰符 / 不删类)。新插件放心引用。
  2. experimental:新提取 / 接口可能调整。文档标注,引用建议锁定版本。
  3. 首版基线(wolai 提取的通用组件)即 stable;后续新提取先 experimental,经 1~2 个插件验证后转正。

6. 文件分层规则

来源:总纲 §3.1 + 演进 §7

  1. 四固定层:pvq-ui(base) / pvq-ui-admin / pvq-ui-editor / pvq-ui-frontend。
  2. 新场景 → 新增 pvq-ui-<scene>.css,不塞进 base。
  3. 所有层共享 base 的 --pvq-* 令牌,跨场景风格一致。
  4. 组件视觉依赖 FontAwesome:loader 保证 font-awesome 句柄注册,pvq-ui-admin 声明对其依赖。

7. 消费方接入规则

来源:总纲 §8/§10 + 调用手册

  1. 每个插件只需:复制 pvq-ui-loader.php → require_once → PVQ_UI_Loader::enqueue( $scenes )(不传版本,版本由站点级 PVQ_UI_VERSION 决定,见 §4.3)。不得各写一份收敛 / 注册逻辑。
  2. 插件自身样式声明对 pvq-ui / pvq-ui-<场景> 的依赖,不复制库样式。
  3. 内网站点可用 PVQ_UI_URL 等常量覆盖为本地副本。
  4. 插件不得硬编码库版本号字面量(如 enqueue( array('admin'), '1.2.10' ))——它会成为全站版本的"先到先得"钉子(§4.3);插件自有的版本常量(如用于界面展示的 PVQ_WR_UI_VER)可以保留,但不要把它当作控制全站库版本的手段。

8. 提交 / 同步纪律

  1. 改动前先确认文档已更新(§1)。
  2. 改动后:bump 版本(§4)→ 按 §1.3 版本七处同步 → 同步 CHANGELOG.md(含组件加入 / stable 转正记录)→ 同步 site/inc/components.json 与模块文档的稳定性标记 → 同步 readme.md。
  3. 迁移插件时:按总纲 §9 步骤,最后做 grep 防回潮校验(§2.2)。

9. 违规处理

  • 发现插件自建通用组件副本 → 回流到库(先文档、后代码),删插件副本,grep 校验。
  • 发现 inline handler / 非 BEM 命名 / 硬编码色值 → 改造时一并修正,不新增债务。
  • 发现版本号三处不一致 → 立即对齐。