urit-qf-ui
v0.2.5
Published
基于 ElementPlus 的业务组件库(UMenu / TableRender / FormRender / UInput 等)
Readme
urit-qf-ui
基于 ElementPlus 的业务组件库(UMenu / TableRender / FormRender / UInput 等)
读者:接手这个前端底座的使用方开发者 / AI 编码助手。 本文只讲**「怎么把它装进你的工程、样式从哪来、踩了什么坑怎么修」**。 各组件的字段级用法见:
doc/菜单渲染器使用手册.md、doc/表格渲染器使用手册.md、doc/表单渲染器使用手册.md。
0. 四条铁律
- 引 npm 包时,样式必须显式引入:
import 'urit-qf-ui/style.css'。不写这行 → 组件功能正常、样式全丢(最容易踩、且控制台无任何报错)。 - peerDependencies 要自己装,包管理器不会自动装。至少:
vue、element-plus、@element-plus/icons-vue、axios、mitt、mqtt、dayjs。 - 引源码(alias 到
qfui/src)时不需要引style.css,样式随 SFC 自带;但必须配resolve.dedupe,否则会出现两份 Vue / element-plus 实例。 - 从「引源码的工程」往「引 npm 包的工程」拷页面时,样式不会跟着过去,一定要回目标工程的
main.ts补第 1 条那行 import。
0.5 后端地址:默认「免配」,也可以配 baseUrl
库里的 Http(src/qf/http.ts)按这个优先级决定接口往哪发:
| 优先级 | 来源 | 什么时候用 |
|--------|------|-----------|
| 1 | QfOptions.baseUrl(public/config/config.json → qfOptions.baseUrl) | 前后端不同机/不同端口/走网关 —— 配了就以它为准 |
| 2 | document.baseURI 的 origin | 免配默认值:后端 = 前端的 IP + 端口 |
| 3 | window.$wujie.location.origin | 无界沙箱里取不到 <base> 时的兜底 |
| 4 | window.location.origin | 最后兜底 |
// 想改地址,只动 config.json(不用改代码)
{ "qfOptions": { "baseUrl": "http://192.168.1.9:8085", ... } }需要自己发请求、或想拿「本应用自己的根地址」时,用库里导出的同一个函数:
import {resolveBaseUrl} from 'urit-qf-ui'
const root = resolveBaseUrl() // 独立运行 = 本站 origin;被无界嵌入 = 子应用自己的 origin⚠️ 被无界(wujie)以微前端方式嵌入时,绝对不能用 window.location.origin 拼接口地址。
沙箱 iframe 的 src 是 blob: 空页(与主应用同源),子应用里的 window.location.origin
拿到的是主应用的域名/端口 → 请求会打到主应用去。实测(主应用 8111、子应用 8009):
| 写法 | 无界里 resolveBaseUrl() | 免配请求实际打到 |
|------|--------------------------|------------------|
| window.location.origin(≤0.2.4 的老写法) | http://127.0.0.1:8111 ❌ | http://127.0.0.1:8111/api/...(主应用) |
| document.baseURI(0.2.5 起) | http://127.0.0.1:8009 ✅ | http://127.0.0.1:8009/api/...(子应用自己) |
无界会给子应用注入正确的 <base>,所以 document.baseURI 在「独立运行」和「被嵌入」两种态下都指向应用自己。
1. 安装
npm i urit-qf-ui
# peerDependencies(不会自动安装)
npm i vue element-plus @element-plus/icons-vue axios mitt mqtt dayjs2. 引入(两种方式,二选一)
方式 A · 引 npm 包(正式工程用这个)
// main.ts
import 'element-plus/dist/index.css'
import 'urit-qf-ui/style.css' // ← 必须!少这行 = 只有 DOM 没有样式<!-- 页面里 -->
<script setup lang="ts">
import {UMenu, TableRender, FormRender} from 'urit-qf-ui'
import type {MenuClickPayload} from 'urit-qf-ui'
</script>若打包器不认
exports字段,退回写完整路径import 'urit-qf-ui/dist/style.css'。
方式 B · 引源码(改库时要热更新调试时用)
// vite.config.ts
resolve: {
dedupe: ['vue', 'vue-router', 'element-plus', '@element-plus/icons-vue', 'mitt', 'axios', 'dayjs'],
alias: {
'urit-qf-ui': fileURLToPath(new URL('../../sw_cp_qfui/qfui/src', import.meta.url)),
// 或简写成 'qfui',手册里的示例代码用的是这个短名
}
}此方式不需要引 style.css(每个 SFC 自带 <style scoped lang="scss">),改组件后热更新即时生效。
3. 为什么 npm 包必须手写那行 import(事实,不是玄学)
库用 Vite lib 模式打包,产物是:
| 文件 | 内容 |
|------|------|
| dist/index.js | 纯 JS。各 SFC 的 <style scoped> 已被抽取走,文件里没有任何 CSS 注入代码(style.css / appendChild / document.head 出现次数均为 0),只保留了对外部依赖 element-plus/dist/index.css 的 import |
| dist/style.css | 全部组件样式(约 11.8 KB,23 个 data-v-* scopeId) |
| package.json | 未配 style 字段、未声明 CSS 副作用 → 没有任何工具会自动帮你引 |
所以 import {UMenu} from 'urit-qf-ui' 拿到的是"无壳组件"。这与 Element Plus 需要 import 'element-plus/dist/index.css' 是完全同一回事。
引源码为什么没事:组件源码里 <style scoped> 和 template 在同一文件,Vite 编译 SFC 时样式自动注入。
4. 排错表(现象 → 原因 → 修法)
| 现象 | 原因 | 修法 |
|------|------|------|
| 功能正常、样式全丢:左侧菜单没宽度/背景、菜单项挤在左上角、搜索表单 label 与输入框重叠、表格无边框、按钮错位,控制台零报错 | 引了 npm 包但没引它的样式 | 目标工程 main.ts 加 import 'urit-qf-ui/style.css' |
| 引了 style.css 但样式仍不对 | 工程里存在两份 urit-qf-ui(或 dist 与 src 混用),data-v-* scopeId 对不上 | 统一只留一种引入方式;用下面的命令核对 scopeId |
| Failed to resolve import "mqtt" | mqtt 是 peerDependency,未自动安装,但产物里有 import mqtt | npm i mqtt@^5.15.2 → 删 node_modules/.vite → 重启 dev server |
| <el-select> 下拉选项一个都不显示,且无任何报错 | 出现两个 Vue / element-plus 实例(alias 引源码时,qfui/src 里的 import 'vue' 解析到了 qfui/node_modules 的另一份) | resolve.dedupe 加上 vue、vue-router、element-plus、@element-plus/icons-vue、mitt、axios、dayjs |
| 弹层(下拉 / 日期 / 消息框)被挡住不显示 | 页面引了 Quasar 的 quasar.css,.fullscreen 带 position:fixed; z-index:6000 | 自己项目的 css 里覆盖 .fullscreen{z-index:auto !important};根容器别加 .fullscreen 类 |
| 改完库源码,页面没变化 | 工程引的是 npm 包(node_modules 里的旧 dist),不是源码 | 要么改成 alias 引源码(方式 B),要么重新 npm run build + 覆盖 dist + 删 node_modules/.vite |
| 每页条数一多(≥20)表格就一路撑长,分页条被顶出容器、点不到;机构详情里的子表也把面板撑长 | 0.2.3 的 .table-grid(TableGrid.vue 根节点)没参与 .table-container 的 flex 分配,而 EP 的 .el-table 默认 height: fit-content | 升级到 0.2.4+(该规则已内置到 TableRender.vue)。仍在旧版就在项目全局样式里补:.table-render .table-container .table-grid{flex:1;min-height:0;max-height:var(--table-grid-max-height,none)} + .table-render .table-container .table-grid>.el-table{height:100%};详见《表格渲染器使用手册》第 8 节 |
| 被无界嵌入后,接口全打到主应用去(浏览器 Network 里请求域名/端口 = 主应用,改 config.json 的 baseUrl 又能通) | ≤0.2.4 的 Http 用 window.location.origin 兜底,而无界沙箱 iframe 是 blob:(与主应用同源)→ 拿到的是主应用 origin | 升级到 0.2.5+(改用 document.baseURI),见 §0.5;临时可在页面里自己拼地址并显式传 baseUrl |
| 详情面板给了 #detail-extra 插槽后,YAML 里配的字段列表不见了 | 0.2.5 起 detail-extra 改为接管语义(默认 replace) | 想「字段列表 + 插槽共存」就加 detail-extra-mode="append";详见《表格渲染器使用手册》5.4 |
| 点表单弹窗「取消」,对话框高度先塌一截再淡出 | 内容被 v-if="visible" 立刻卸载,而 el-dialog 是「先播退场动画、播完才移除 DOM」 | 升级到 0.2.5+(库内已改为内容常驻、清状态放 @closed);详见《表单渲染器使用手册》附录 A #9 |
| 点「预览」(action: preview)/ 关详情抽屉,浮层唰一下就没、完全没有滑出动画 | 预览抽屉写成了 <el-drawer v-if="previewVisible" :model-value="true"> —— v-if 挂在可见性上:关的时候组件当场被卸载,el-drawer 的退场过渡根本没机会播(实测:leave-active 那一帧抽屉已不在,内容项数 4 → 0) | 升级到 0.2.5+(库内已改为「挂载开关 previewMounted」与「显隐开关 previewVisible」分离,内容清理放 @closed)。自己项目里若也有这类 v-if="visible" 的浮层,按同样思路拆开 |
验证样式真的进来了(10 秒)
# 1) 确认产物里 JS 与 CSS 是配套的:输出应为 "23 []" —— 23 个 scopeId 全部能在 index.js 里找到
node -e "const fs=require('fs');const c=fs.readFileSync('node_modules/urit-qf-ui/dist/style.css','utf8'),j=fs.readFileSync('node_modules/urit-qf-ui/dist/index.js','utf8');const h=[...new Set([...c.matchAll(/data-v-([0-9a-f]{8})/g)].map(m=>m[1]))];console.log(h.length, h.filter(x=>!j.includes('data-v-'+x)))"
# 2) 跑起页面后,F12 → Elements 里搜 data-v- ,能看到 .u-menu[data-v-xxxx] 这类规则就说明样式进来了5. 开发调试(改本库源码)
预览组件效果
组件源码在 src/components/,预览页面在 examples/。
cd qfui
npm install
npm run example然后访问 http://localhost:5173/examples/
在 examples/App.vue 中添加或修改组件预览。
添加新组件
- 在
src/components/创建组件文件 - 在
src/index.ts中导出组件 - 在
examples/App.vue中添加预览 - 运行
npm run example查看效果
构建发布
# 构建 npm 包
npm run build
# 发布到 npm
npm publish发布前检查清单
- 跑
release.bat(=release.py:先npm run build,再让你选 patch / minor / major 并发布);手动发布才需要自己改package.json的version再npm publish - 确保
src/index.ts导出了所有组件 - 运行
npm run build构建 - 确认
dist/style.css已生成且非空(本库样式全靠它,缺失 = 使用方全部无样式) - 运行
npm publish发布 - 发布后提醒使用方:升级版本 → 删各自
node_modules/.vite→ 重启 dev server(vite 会把依赖 CSS 内联进预构建产物,不清缓存会继续用旧样式) - (可选但推荐)发布后拉 tarball 核验产物:版本号对 ≠ 内容对。把
https://registry.npmjs.org/urit-qf-ui/-/urit-qf-ui-<版本>.tgz下载解压,比对dist/index.js、dist/index.umd.cjs、dist/style.css三个文件与本地dist的 md5 —— 必须全等,否则说明发布的是另一份构建
