@done-coding/admin-core 0.31.0 → 0.31.1-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/bridge/config-hook.mjs +3 -0
- package/es/bridge/index.mjs +6 -0
- package/es/bridge/theme/index.mjs +11 -3
- package/es/components/app-layout/AppBody.vue.mjs +1 -1
- package/es/components/app-layout/AppBody.vue2.mjs +2 -2
- package/es/components/app-layout/AppPage.vue.mjs +1 -1
- package/es/components/app-layout/AppPage.vue2.mjs +175 -33
- package/es/components/app-layout/AppPageNavBar.vue.mjs +7 -0
- package/es/components/app-layout/AppPageNavBar.vue2.mjs +148 -0
- package/es/components/app-layout/app-page-geometry.mjs +3 -2
- package/es/components/app-layout/app-page-slot-surface.mjs +31 -0
- package/es/components/app-layout/use-app-page-title-field.mjs +41 -0
- package/es/components/data-view/DataGridView.vue.mjs +1 -1
- package/es/components/data-view/DataGridView.vue2.mjs +2 -1
- package/es/components/data-view/DataListView.vue.mjs +1 -1
- package/es/components/data-view/DataListView.vue2.mjs +14 -9
- package/es/components/data-view/DataListViewItem.vue.mjs +1 -1
- package/es/components/data-view/DataListViewItem.vue2.mjs +3 -1
- package/es/components/data-view/InfiniteListView.vue.mjs +1 -1
- package/es/components/data-view/InfiniteListView.vue2.mjs +25 -18
- package/es/components/data-view/use-grid-layout.mjs +13 -15
- package/es/components/display/TabsMain.vue.mjs +3 -1
- package/es/components/display/use-badge.mjs +10 -3
- package/es/components/form/FormItem.vue.mjs +1 -1
- package/es/components/form/FormMain.vue.mjs +1 -1
- package/es/components/form/FormMain.vue2.mjs +11 -4
- package/es/components/form/FormSearch.vue.mjs +1 -1
- package/es/components/form/FormSearch.vue2.mjs +12 -4
- package/es/components/form/FormSubmitPanel.vue.mjs +1 -1
- package/es/components/form/FormSubmitPanel.vue2.mjs +2 -0
- package/es/components/form/use-ai-fill.mjs +7 -1
- package/es/components/list-layout/ListLayout.vue.mjs +1 -1
- package/es/components/list-layout/ListLayout.vue2.mjs +19 -10
- package/es/components/modal/ModalConfirm.vue.mjs +1 -1
- package/es/components/modal/ModalConfirm.vue2.mjs +28 -5
- package/es/components/table/TableToolbar.vue.mjs +1 -1
- package/es/components/table/TableToolbar.vue2.mjs +15 -1
- package/es/components/view-layout/ViewLayout.vue.mjs +1 -1
- package/es/components/view-layout/ViewLayout.vue2.mjs +22 -29
- package/es/components/view-layout/ViewLayoutToolbar.vue.mjs +1 -1
- package/es/components/view-layout/ViewLayoutToolbar.vue2.mjs +16 -129
- package/es/config/slot-region.mjs +1 -0
- package/es/hooks/use-surface.mjs +5 -0
- package/es/hooks/use-theme-apply.mjs +18 -0
- package/es/index.mjs +4 -1
- package/es/store/app.mjs +26 -11
- package/es/style.css +230 -172
- package/package.json +2 -2
- package/src/bridge/docs/README.md +19 -3
- package/src/components/app-layout/docs/README-AppBody.md +25 -1
- package/src/components/app-layout/docs/README-AppHeader.md +1 -1
- package/src/components/app-layout/docs/README-AppPage.md +172 -3
- package/src/components/data-view/docs/README-DataListView.md +40 -1
- package/src/components/data-view/docs/README-InfiniteListView.md +68 -4
- package/src/components/display/docs/README-BadgeMark.md +18 -10
- package/src/components/form/docs/README-FormMain.md +26 -0
- package/src/components/list-layout/docs/README-ListLayout.md +12 -1
- package/src/components/menu/README.md +1 -1
- package/src/components/modal/docs/README-ModalConfirm.md +57 -0
- package/src/components/view-layout/docs/README-ViewLayout.md +46 -129
- package/types/bridge/config-hook.d.ts +5 -2
- package/types/bridge/index.d.ts +22 -0
- package/types/components/app-layout/AppPage.vue.d.ts +43 -1
- package/types/components/app-layout/AppPageNavBar.vue.d.ts +48 -0
- package/types/components/app-layout/app-page-geometry.d.ts +27 -2
- package/types/components/app-layout/app-page-slot-surface.d.ts +18 -0
- package/types/components/app-layout/index.d.ts +1 -0
- package/types/components/app-layout/types.d.ts +37 -1
- package/types/components/app-layout/use-app-page-title-field.d.ts +49 -0
- package/types/components/data-view/DataListViewItem.vue.d.ts +7 -0
- package/types/components/data-view/types.d.ts +26 -3
- package/types/components/data-view/use-grid-layout.d.ts +31 -6
- package/types/components/form/types.d.ts +8 -2
- package/types/components/list-layout/ListLayout.vue.d.ts +23 -2
- package/types/components/list-layout/types.d.ts +7 -0
- package/types/components/view-layout/ViewLayout.vue.d.ts +4 -16
- package/types/components/view-layout/ViewLayoutToolbar.vue.d.ts +3 -9
- package/types/components/view-layout/types.d.ts +11 -50
- package/types/config/slot-region.d.ts +17 -1
- package/types/injectInfo.json.d.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@done-coding/admin-core",
|
|
3
|
-
"version": "0.31.0",
|
|
3
|
+
"version": "0.31.1-alpha.0",
|
|
4
4
|
"description": "内部前端库",
|
|
5
5
|
"private": false,
|
|
6
6
|
"main": "es/index.mjs",
|
|
@@ -83,5 +83,5 @@
|
|
|
83
83
|
"dependencies": {
|
|
84
84
|
"@tanstack/vue-virtual": "^3.13.35"
|
|
85
85
|
},
|
|
86
|
-
"gitHead": "
|
|
86
|
+
"gitHead": "56d3873297ddb41aadc8ec41d3a222f038f8d2f7"
|
|
87
87
|
}
|
|
@@ -96,9 +96,9 @@ type BadgeEntry = {
|
|
|
96
96
|
visible?: boolean;
|
|
97
97
|
} & (
|
|
98
98
|
| { kind: "count"; value: number; max?: number } // 数字角标
|
|
99
|
-
| { kind: "new" } //
|
|
100
|
-
| { kind: "updated" } //
|
|
101
|
-
| { kind: "beta" } //
|
|
99
|
+
| { kind: "new" } // 新
|
|
100
|
+
| { kind: "updated" } // 更新
|
|
101
|
+
| { kind: "beta" } // 内测:能用,不稳定
|
|
102
102
|
| { kind: "wip" } // 开发中:仅提示,**不拦点击**
|
|
103
103
|
| { kind: "planned" } // 规划中:还没开工
|
|
104
104
|
| { kind: "deprecated" } // 待下线
|
|
@@ -249,6 +249,22 @@ appCoreBridge.update("APP_LAYOUT_SIDEBAR_CONFIG", { menuGroupMode: true });
|
|
|
249
249
|
|
|
250
250
|
适用判据与三级菜单的混合渲染规则见 [menu 族文档](../../components/menu/README.md) 与 [AppSidebar 文档](../../components/app-layout/docs/README-AppSidebar.md)。
|
|
251
251
|
|
|
252
|
+
## 主题预设的 `layout.body.shimPadding` 会被就地摘掉(v0.32.0)
|
|
253
|
+
|
|
254
|
+
`setStyle` → `applyLayout` 叠加 preset 的布局 partial 时,**`body.shimPadding` 不灌进 bridge**,
|
|
255
|
+
而是就地忽略 + 单独 `console.warn`(带 preset id)。
|
|
256
|
+
|
|
257
|
+
- **为什么**:该字段自 `huhyx7` 起**零渲染消费**,core 里唯一的消费者就是 `AppBody` 的那条
|
|
258
|
+
废弃告警 ⇒ 灌进去的唯一后果是「**下游哪怕自己配了空对象也被恒刷告警、关不掉**」。
|
|
259
|
+
消费方 `qd-ai-aigc` 自 core 0.28 就删干净了,照样每次进页被点名,一路 grep 到
|
|
260
|
+
`node_modules` 才发现是内置预设在写(32 套写了 14–32 的死值,v0.32.0 已全量清空)。
|
|
261
|
+
- **摘掉是零视觉变化**:它本就是死值(`AppBody` 注释写明内容矩形 inset 不含它)。
|
|
262
|
+
🔴 [MUST NOT] 为「保住原观感」去改 preset 的 `layout.gap.size` —— 那个旋钮**按比例缩放四档
|
|
263
|
+
间距**,会改掉该 preset 下**所有**间距,是拿一个不存在的问题换一个真的问题。
|
|
264
|
+
- **`body` 的其余字段照常叠加**(如 `background`)—— [MUST NOT] 把整个 `body` 一起丢掉。
|
|
265
|
+
- 连带:`AppBody` 那条告警因此**只剩两个来源**(`createCoreBridge` 配置 / 路由 meta),
|
|
266
|
+
文案已改为直接列全,见 [README-AppBody](../../components/app-layout/docs/README-AppBody.md)。
|
|
267
|
+
|
|
252
268
|
## 展开菜单到某路径(`bridge.layout.openMenuTo`)
|
|
253
269
|
|
|
254
270
|
```ts
|
|
@@ -52,13 +52,37 @@ AppBody 由 AppLayout 自动装配,无需手动挂载——总装配见 AppLay
|
|
|
52
52
|
- 🔴 [MUST NOT] 在业务侧用 `!important` 压 `.app-body` 的背景;更 [MUST NOT] 拿它去铺一层
|
|
53
53
|
**"与全局底同色"** 的面 —— 那是把一个会变的值复制到第二处,换底 / 换主题时必留补丁
|
|
54
54
|
(同 AppPage 文档那条)。要改底色,改的是**主题的 `bodyColor`**(底由它派生),不是在这里补色。
|
|
55
|
+
- **内容 ↔ chrome 让「外圈档」,内容 ↔ viewport 边让「模块档」**(r8kvnd 更正,v0.32.0)。
|
|
56
|
+
原口径把两者当成同一件事(都算「内容对外」)—— 其实是两件:
|
|
57
|
+
**没有 chrome 时,内容接替的是 chrome 的角色(最外层元素)**,就该拿 chrome 贴边那一档。
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
有侧栏: 视口边 ─模块档─ sidebar ─外圈档─ 内容 ← 外圈档量的是「内容 ↔ chrome」,对
|
|
61
|
+
无侧栏: 视口边 ─模块档─ 内容 ← 这一档顶替的是 sidebar 的位置
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
⇒ **最外层到视口边恒为模块档**,不再随有没有 chrome 在 8 / 16 之间跳。
|
|
65
|
+
改的是**左 / 右 / 上**三条(都是条件分支,只影响隐藏了对应 chrome 的页面);
|
|
66
|
+
⚠️ **底边暂未改**:它是**无条件**的(`footer` 在流内),动它全仓每页都变,待甲方拍板。
|
|
67
|
+
🔴 `contentViewportInset` 与 `bodyShimStyle.minHeight` [MUST] 同步改 ——
|
|
68
|
+
它们与 `bodyStyle` padding **同源同条件**,只改样式就是
|
|
69
|
+
「视觉对了但 `viewportHeight` / `contentInset` 算错」的静默偏差。
|
|
70
|
+
|
|
55
71
|
- **内容四周留白 = 间距阶梯的「外圈档」**(`gap × 2`,默认 16)。它**接替了已废弃的
|
|
56
72
|
`APP_LAYOUT_BODY_CONFIG.shimPadding`** —— 此前这段空白由 `gap + shimPadding` 两个来源
|
|
57
73
|
各给一半,`akw76r` 让容器层露底后两者在视觉上就是同一段空白,冗余由此产生。
|
|
58
74
|
- `.app-body-shim` **不再铺 padding**(恒 0)。
|
|
59
|
-
-
|
|
75
|
+
- 有 chrome 的那一侧:内容偏移 = `模块档 + chrome 高 + 外圈档`;**没有 chrome 的那一侧 = 模块档**(见上条)。
|
|
60
76
|
- `shimPadding` 配了非 0 值只会得到一条 `console.warn`,不影响渲染。要调留白 ⇒ 改
|
|
61
77
|
`APP_LAYOUT_GAP_CONFIG.size`(一个旋钮按比例缩放四档)。
|
|
78
|
+
- 🔴 **那条告警说得出来源**(v0.32.0,hhae5s):能走到它的**只剩两个**入口 ——
|
|
79
|
+
① `createCoreBridge` 的 `APP_LAYOUT_BODY_CONFIG.shimPadding`;
|
|
80
|
+
② 当前路由的 `meta.layout.bodyShimPadding`(优先级更高)。
|
|
81
|
+
**主题预设那一路不会走到这里** —— preset 的 `layout.body.shimPadding` 在
|
|
82
|
+
`bridge/theme` 的 `applyLayout` 里就**就地摘掉 + 单独点名**(带 preset id),
|
|
83
|
+
[MUST NOT] 再灌进 bridge。
|
|
84
|
+
动因:消费方自 core 0.28 就把该键删干净、配的是空对象,**照样每次进页被点名且关不掉**,
|
|
85
|
+
一路 grep 到 `node_modules` 才发现是内置预设在写(32 套写了 14–32 的死值,已全量清空)。
|
|
62
86
|
- 🔴 **chrome 模块彼此**(header ↔ sidebar ↔ footer ↔ 外框)仍取**模块档 ×1** ——
|
|
63
87
|
只有「内容对外」才 ×2。[MUST NOT] 把两者拉平:拉平后 sidebar 会被一起推开,chrome 的节奏就散了。
|
|
64
88
|
- **完整能力演示**(NoBreadcrumb/NoFooter/NoHeader/NoSidebar 显隐变体):`apps/reference/src/pages/app-layout/layout/`
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
## 模块条徽标(badge)
|
|
16
16
|
|
|
17
|
-
模块条的每一项以其路由 **`path` 为 key** 查 `bridge.badge` 注册表,命中则渲染绝对定位角标(数量 /
|
|
17
|
+
模块条的每一项以其路由 **`path` 为 key** 查 `bridge.badge` 注册表,命中则渲染绝对定位角标(数量 / 新 / 更新 / 内测 / 开发中 / 自定义),**不压字、不改变宿主尺寸**;未命中零影响、无需在菜单数据里加字段。
|
|
18
18
|
|
|
19
19
|
与 AppSidebar 菜单树同一份注册表、同一套 key 规则——同一个 `path` 在两处显示同一个标。
|
|
20
20
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AppPage(页面容器·撑满视口 + 四向悬浮插槽)
|
|
2
2
|
|
|
3
|
-
> 页面主体容器:默认 slot 按视口高变量撑满(min-height/height 双模式),#top/#bottom/#left/#right 四向 fixed 悬浮插槽(shim 呼吸 + gap
|
|
3
|
+
> 页面主体容器:默认 slot 按视口高变量撑满(min-height/height 双模式),#top/#bottom/#left/#right 四向 fixed 悬浮插槽(shim 呼吸 + gap 间距),超宽屏内容限宽居中,**页面级 navbar(返回 / 标题 / ⋮ / tabbar)**。
|
|
4
4
|
> 范式页:`apps/reference/src/pages/app-layout/page-slots/`(四向悬浮槽 + ChainReadout 高度链互动面板)
|
|
5
5
|
|
|
6
6
|
## 定位
|
|
@@ -41,6 +41,10 @@
|
|
|
41
41
|
## 能力边界 / 按需使用
|
|
42
42
|
|
|
43
43
|
- **四向悬浮插槽(`#top`/`#bottom`/`#left`/`#right`):默认全关、常规页面不需要。** 仅当页面需要「悬浮于内容之上的固定补充区」(通栏操作条 / 侧边抽屉 / 浮动提示)才开对应槽——判据:内容必须 fixed 悬浮且不参与文档流(top/bottom 通栏量高 → padding 让位,left/right 量宽)。列表/表单/详情常规页一律不开。**`#left`/`#right` 内放列表时用 scope 的 `listLayoutRecommended`(见 API)拿窄栏推荐配置,[MUST NOT] 自行拍脑袋配窄栏列表形态。**
|
|
44
|
+
- **`showNavBar`(页面级 navbar):默认关。** 仅移动端形态 / 需要页头返回与 ⋮ 的页面才开。
|
|
45
|
+
🔴 **navbar 归 `AppPage` 不归内容容器**(`vq3mzn`):它是 **page chrome**,一页恒一个;
|
|
46
|
+
做在 `ViewLayout` / `ListLayout` 上会出「一页两个 navbar」(split 档同页两个容器)、
|
|
47
|
+
且只盖住自己那半边。`ViewLayout.appBar` 已因此**摘除**(v0.32.0 breaking,见 migrations)。
|
|
44
48
|
- **`contentCentered`(超宽屏限宽居中):默认关,按页面类型开。** 表单页 / 详情页 / 阅读型页开(超宽屏下内容整行铺满,label↔控件、行首↔行尾视线跨度过长);**列表 / 表格页 [MUST NOT] 开**——表格列本就挤,限宽后更挤(业界同解:GitHub 对 diff / 表格页保留全宽)。`contentMaxWidth` 仅在需要非 1200 时设。
|
|
45
49
|
- `topBg`/`bottomBg`/`leftBg`/`rightBg`:**默认已是面色**(`--el-bg-color`),不用设。
|
|
46
50
|
只在要**换色**(品牌色条)或要**关掉面**(`"transparent"`,让底透上来)时才传。
|
|
@@ -63,7 +67,7 @@
|
|
|
63
67
|
| `leftWidth` / `rightWidth` | `string?` | — | `#left` / `#right` 槽的**显式宽度**(CSS 长度串)。缺省不写 ⇒ 槽宽跟内容走(shrink-to-fit,老行为)。🔴 **槽内内容要用百分比宽时 [MUST] 改用本 prop**,见下 |
|
|
64
68
|
| `contentMaxWidth` | `number` | `1200` | 限宽值(px),仅 `contentCentered` 开启时生效 |
|
|
65
69
|
| `gap` | `number` | `8` | 间距基数 px(缺省读 bridge `APP_LAYOUT_GAP_CONFIG.size`)。**槽 ↔ 内容**与**槽 ↔ 槽**都取由它派生的「外圈档」(`基数 × 2`,随密度缩放),两处同式同源 |
|
|
66
|
-
| `topBg` / `bottomBg` / `leftBg` / `rightBg` | `string` | `var(--el-bg-color)`(面色) | 各槽 shim 背景;传 `"transparent"` 可关。**shim 自带圆角**(`--dc-core-radius`,随主题;无 bg
|
|
70
|
+
| `topBg` / `bottomBg` / `leftBg` / `rightBg` | `string` | `var(--el-bg-color)`(面色) | 各槽 shim 背景;传 `"transparent"` 可关。**shim 自带圆角**(`--dc-core-radius`,随主题;无 bg 的槽透明、圆角无视觉影响)。⚠️ **显式传值会关掉「面下放」**(见下) |
|
|
67
71
|
|
|
68
72
|
> **五个背景 prop 的契约(分两组,判据是「块」还是「容器」)**
|
|
69
73
|
>
|
|
@@ -80,10 +84,22 @@
|
|
|
80
84
|
>
|
|
81
85
|
> **默认插槽恒透明**,且没有给它上色的 prop —— 它是主内容区,必须让底透上来。
|
|
82
86
|
| `topObserveResize` / `bottomObserveResize` / `leftObserveResize` / `rightObserveResize` | `boolean` | 均 `false` | 逐槽 WatchSize RO 观测(CSS 过渡折叠等非重渲染尺寸变化时开) |
|
|
87
|
+
| `showNavBar` | `boolean` | `false` | 开启**页面级 navbar**(返回 / 标题 / ⋮ / tabbar),见下 |
|
|
88
|
+
| `back` | `() => void` | — | 给了才渲染左侧返回箭头(热区 ≥44×44)。**仅 `showNavBar` 开启时** |
|
|
89
|
+
| `moreOptions` | `AppPageNavBarMoreOption[]` | — | ⋮ 的下拉菜单项;给了即点击开菜单 |
|
|
90
|
+
| `onMoreSelect` | `(item) => void` | — | 菜单项点选回调 |
|
|
91
|
+
| `onMore` | `() => void` | — | 无菜单时 ⋮ 的直接点击回调 |
|
|
92
|
+
| `navBarObserveResize` | `boolean` | `false` | navbar 的 WatchSize RO 观测(tabbar 有过渡折叠等非重渲染高度变化时开) |
|
|
93
|
+
|
|
94
|
+
### v-model
|
|
95
|
+
|
|
96
|
+
| 名 | type | 语义 |
|
|
97
|
+
| --- | --- | --- |
|
|
98
|
+
| `title` | `string \| undefined` | navbar 标题。子层经 `titleField.changeTitle()` 写回,消费方经本 model 拿得到。⚠️ **不开 `showNavBar` 时值照改、只是没有显示位** |
|
|
83
99
|
|
|
84
100
|
### Emits
|
|
85
101
|
|
|
86
|
-
|
|
102
|
+
无(`onMoreSelect` / `onMore` 是 props 形态的回调,见上)
|
|
87
103
|
|
|
88
104
|
### Slots
|
|
89
105
|
|
|
@@ -92,6 +108,118 @@
|
|
|
92
108
|
| `default` | 无 | 页面主体(ModalShelf page 层包裹) |
|
|
93
109
|
| `#top` / `#bottom` | 无 | 通栏悬浮槽(量高 → padding-top/bottom) |
|
|
94
110
|
| `#left` / `#right` | `{ listLayoutRecommended }` | 侧向悬浮槽(量宽)——scope 携带窄栏 ListLayout 推荐配置(见下) |
|
|
111
|
+
| `#navTitle` | `{ title }` | navbar 标题位自定义(缺省渲染 `title`)。仅 `showNavBar` 开启时 |
|
|
112
|
+
| `#more` | 无 | ⋮ 的图标位自定义(缺省 `MoreFilled`)。⚠️ 点击绑在**外层 `span`** 上 ⇒ 本槽 [MUST] 放哑内容 |
|
|
113
|
+
| `#tabbar` | 无 | navbar **第二行**(标签栏)。🔴 [MUST NOT] 改放 `#header` —— 见下 |
|
|
114
|
+
|
|
115
|
+
## 页面级 navbar(`showNavBar`)
|
|
116
|
+
|
|
117
|
+
```vue
|
|
118
|
+
<AppPage
|
|
119
|
+
v-model:title="title"
|
|
120
|
+
show-nav-bar
|
|
121
|
+
:back="() => router.back()"
|
|
122
|
+
:more-options="[{ label: '分享', value: 'share' }, { label: '删除', value: 'remove' }]"
|
|
123
|
+
:on-more-select="(item) => handle(item.value)"
|
|
124
|
+
>
|
|
125
|
+
<template #tabbar><ElTabs v-model="tab">…</ElTabs></template>
|
|
126
|
+
<ViewLayout :api="api" />
|
|
127
|
+
</AppPage>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 🔴 为什么 navbar 归 `AppPage`,不归内容容器
|
|
131
|
+
|
|
132
|
+
navbar 是 **page chrome**:**一页恒一个**、横跨整页、在内容滚动之外。
|
|
133
|
+
早先做在 `ViewLayout` 的 toolbar 上(`x2bfq9` / `pfdnd7`),当时的依据是「toolbar 已支持
|
|
134
|
+
title、很平滑」—— **那只回答了「省事吗」,没回答「属于谁」**。三条代价都已发生或必然发生:
|
|
135
|
+
|
|
136
|
+
| # | 代价 |
|
|
137
|
+
| --- | --- |
|
|
138
|
+
| ① | **N 个族各做一遍** —— `ListLayout` 也要 navbar 时就是第二份实现、第二份漂移 |
|
|
139
|
+
| ② | **一页多容器时语义崩** —— 列表详情 split 档同页既有 `ListLayout` 又有 `ViewLayout`,两个都开 ⇒ 一页两个 navbar,而真 navbar 恒一个 |
|
|
140
|
+
| ③ | **覆盖范围不对** —— `ViewLayout` 的 toolbar 只在它自己那个盒内不滚,split 档右侧开 appBar 只盖住右半边 |
|
|
141
|
+
|
|
142
|
+
与 `AppHeader`(布局四区之一的**全局**顶栏:品牌 / 用户)**不同层级**:
|
|
143
|
+
`AppHeader` 管整个应用,navbar 管**这一页**。
|
|
144
|
+
|
|
145
|
+
### 🔴 [MUST NOT] 拿 `#top` 槽自己拼一个
|
|
146
|
+
|
|
147
|
+
`#top` 是**方位槽**(`fixed` + 自带面色 / 圆角 / padding,且有空壳误用检测),
|
|
148
|
+
放消费方自己的东西。navbar 塞进去就没有共享实现可言 —— 等于把拼装成本推给每个消费方。
|
|
149
|
+
|
|
150
|
+
### 🔴 tabbar 是 navbar 的一部分,[MUST NOT] 塞进 `#header`
|
|
151
|
+
|
|
152
|
+
`#header` 是**内容区的标题行**(`ViewLayout` / `ListLayout` 各有一个),
|
|
153
|
+
navbar 是**页面 chrome** —— **同名不同物**,与 `#bottom`(页面级)vs `#detailBottom`
|
|
154
|
+
(详情区内部)是同一类坑。一个槽兼两种语义,下游第一天就会搞混。
|
|
155
|
+
|
|
156
|
+
### 几何:navbar 是第五条固定带
|
|
157
|
+
|
|
158
|
+
navbar 贴内容矩形上沿,`#top` 槽与左右槽依次**下移**。让位量与四向槽**同式同源**
|
|
159
|
+
(`槽高 + 外圈档`)⇒ 四处出口(槽几何 / 重 provide 的可用高 / `APP_PAGE_CONTENT_INSET` /
|
|
160
|
+
默认内容 `padding-top`)自动一致。
|
|
161
|
+
|
|
162
|
+
- **间距取「外圈档」(`基数 × 2`,默认 16)而非模块档**:间距阶梯对外圈档的定义原文就是
|
|
163
|
+
「**内容 ↔ chrome**」,navbar 正是 page chrome;且四向槽全走同一式 ——
|
|
164
|
+
取模块档会让**同一页上 navbar 与 `#top` 槽两种让位口径并存**。
|
|
165
|
+
- **横向 keyline = 外圈档(默认 16)**,移动端 header 侧距惯例。
|
|
166
|
+
🔴 [MUST NOT] 沿用内容容器那一份(8)—— `9dabaj` 统一 `padXPx` 时把 appBar 那份**有依据的
|
|
167
|
+
16 一起砍了**,返回图标因此落在 8px(甲方报「太靠边」)。
|
|
168
|
+
- **返回图标 `margin-left: -13px`** = `(热区 44 − 图标 18) / 2`:让图标**视觉左缘**正好压在
|
|
169
|
+
keyline 上(Material nav-icon keyline 同法)。⚠️ 改图标字号或热区尺寸都要**重推这个数**。
|
|
170
|
+
- **高度 `min-height: 44px`**,不是固定高:内容(含 tabbar)超出照常撑高。
|
|
171
|
+
|
|
172
|
+
## 子层回写页面标题:`useAppPageTitleField`(能力令牌)
|
|
173
|
+
|
|
174
|
+
**问题**:`ViewLayout` / `ListLayout` 拿到详情数据后才有真标题,要推给页面级 navbar。
|
|
175
|
+
**约束**:要能**防止其他地方乱改**标题 ⇒ 能力令牌 —— 不给令牌就够不着这个通道。
|
|
176
|
+
|
|
177
|
+
```vue
|
|
178
|
+
<script setup>
|
|
179
|
+
import { useAppPageTitleField } from "@done-coding/admin-core";
|
|
180
|
+
|
|
181
|
+
const title = ref();
|
|
182
|
+
const titleField = useAppPageTitleField();
|
|
183
|
+
</script>
|
|
184
|
+
|
|
185
|
+
<template>
|
|
186
|
+
<!-- 同一个句柄同时给页面与子件:给了才够得着 -->
|
|
187
|
+
<AppPage v-model:title="title" show-nav-bar :title-field="titleField">
|
|
188
|
+
<ViewLayout :api="api" :title-field="titleField" />
|
|
189
|
+
</AppPage>
|
|
190
|
+
</template>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
interface AppPageTitleField {
|
|
195
|
+
changeTitle: (t: string | undefined) => void;
|
|
196
|
+
/** Teleport 目标:直接给**元素**,[MUST NOT] 返回 class 字符串 */
|
|
197
|
+
titleBoxRef: Readonly<ShallowRef<HTMLElement | undefined>>;
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### 三条容易走反的口径
|
|
202
|
+
|
|
203
|
+
| # | 口径 | 为什么 |
|
|
204
|
+
| --- | --- | --- |
|
|
205
|
+
| ① | **单句柄**(不拆 `secret` / `remoter`) | 接线点 3 → 2;同名同值传两处,令牌性不丢(不给就够不着),但不会传串、不用分「给页面的那半 / 给子件的那半」 |
|
|
206
|
+
| ② | 失败 = **dev 期点名 `console.warn`**,[MUST NOT] 返回静默 `false` / 空串 | 「标题没变」正是本仓连修四个缺陷的同一形态(`labelHide` 类挂上规则打不中 / 方位槽误用 / 徽标静默 / 引导卡死)。句柄没被任何 `AppPage` 认领 ⇒ 点名 |
|
|
207
|
+
| ③ | 🔴 **[MUST NOT] 校验「子件是 AppPage 的直系子元素」** | 本仓已两次付过代价:`useContextDefaults` 读**直系父 DOM**,消费方在插槽里**包一层 `<div>` 就断链且静默**。`provide/inject` 按**组件树**走、不关心 DOM 层数,那是它的优点;令牌已经管住「谁能改」,DOM 层数管的是另一件事**且管不准**(包一层 div 的人并没有越权,他只是写了个 div) |
|
|
208
|
+
|
|
209
|
+
### 其余口径
|
|
210
|
+
|
|
211
|
+
- `v-model:title` **非必须**:`AppPage` 内部走 `defineModel<string>("title")`,
|
|
212
|
+
子层 `changeTitle` 经它写回 ⇒ 消费方拿得到。
|
|
213
|
+
- **只有 `showNavBar` 才看得见**:不开时值照改、只是**没有显示位**
|
|
214
|
+
([MUST] 记住这条,否则会以为「没生效」)。
|
|
215
|
+
- `titleBoxRef` 的用途 = 放**自定义标题**:
|
|
216
|
+
|
|
217
|
+
```vue
|
|
218
|
+
<script setup>
|
|
219
|
+
const { titleBoxRef } = useAppPageTitleField(); // 解构后模板自动解包
|
|
220
|
+
</script>
|
|
221
|
+
<template><Teleport :to="titleBoxRef"><MyFancyTitle /></Teleport></template>
|
|
222
|
+
```
|
|
95
223
|
|
|
96
224
|
### `#left` / `#right` scope:`listLayoutRecommended`(窄栏 ListLayout 推荐配置)
|
|
97
225
|
|
|
@@ -189,6 +317,47 @@ paddingRight = 右槽让位量 + gutter
|
|
|
189
317
|
🔴 **只「报出来」,[MUST NOT] 顺手改成「空槽就不渲染」** —— 那是行为变更、会动已有页面布局,
|
|
190
318
|
与检测是两件事;真要做得单独一版、走 migrations 说清楚。
|
|
191
319
|
|
|
320
|
+
## 面下放:槽里放 `ListLayout` 时,槽自己不再成面
|
|
321
|
+
|
|
322
|
+
**槽内容里有 `ListLayout` ⇒ 该槽撤面 / 撤圆角 / padding 归 0。**
|
|
323
|
+
|
|
324
|
+
### 为什么
|
|
325
|
+
|
|
326
|
+
`ListLayout` 自带**两张卡**(chrome 卡 + 数据区卡,`huhyx7` 的两卡模型)。
|
|
327
|
+
槽再铺一层面,就是**面套面** —— 与 `p4wrtn`(卡片与容器同色)是同一个病换了一层楼:
|
|
328
|
+
白槽 + 白卡,卡不成其为卡。
|
|
329
|
+
|
|
330
|
+
撤掉之后,侧槽里的卡与**默认内容区**的卡**同口径**(都贴各自盒边),两边反而更一致。
|
|
331
|
+
|
|
332
|
+
### 🔴 判定走 VNode 递归,且 [MUST NOT] 只看直系子
|
|
333
|
+
|
|
334
|
+
```
|
|
335
|
+
app-page-slot-shim
|
|
336
|
+
└ dc-app-page-list-detail-split__list ← 列表详情门面自己插的 wrapper
|
|
337
|
+
└ ListLayout
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
「左槽放列表」最常见的场景**就是经门面进来的**,而门面自己插了一层 wrapper
|
|
341
|
+
⇒ **直系子判定在主战场上恒不命中**。这与 `useAppPageTitleField` 那条
|
|
342
|
+
「[MUST NOT] 校验直系子元素」是同一条教训(本仓已为此付过三次代价)。
|
|
343
|
+
|
|
344
|
+
| 决定 | 为什么 |
|
|
345
|
+
| --- | --- |
|
|
346
|
+
| 按**组件 `name`** 匹配,[MUST NOT] 按组件对象 `===` | dev 读 `core/src`、prod 走 `core/es` 可能是**两个 module instance** ⇒ 恒等匹配**永不命中且不报错** |
|
|
347
|
+
| 判定是**每次渲染求值的函数**,[MUST NOT] 写成 `computed` | 插槽不是响应式依赖,`computed` 恒吃首次缓存 ⇒ 槽内容换掉时判定不跟 |
|
|
348
|
+
| 走 **VNode**,[MUST NOT] 走 DOM / 类名 | 槽的背景是**内联**的,DOM 读到时样式已经落上去了,要改只能 `!important` 硬顶;VNode 侧是在**算样式之前**就知道答案 |
|
|
349
|
+
| 命中**多个** ⇒ dev 点名 + **按不命中处理** | 面该归谁无法判定,[MUST NOT] 猜 |
|
|
350
|
+
|
|
351
|
+
### 出口与边界
|
|
352
|
+
|
|
353
|
+
- **显式传 `leftBg` / `rightBg` 等恒优先**:消费方自己要了面就给面,自动下放让路。
|
|
354
|
+
- **槽内不是 `ListLayout` ⇒ 逐字不变**(面 / 圆角 / padding 都在)。
|
|
355
|
+
- 槽内层 shim 的 padding 取**间距阶梯的模块档**(原先写死 `8px`,不随 gap 基数 /
|
|
356
|
+
密度档变)——默认基数下仍解出 8,**零视觉变化**。
|
|
357
|
+
|
|
358
|
+
⚠️ **[MUST NOT] 给 `ListLayout` 的根投射 padding**:它的**根是透明的**(面在内部两张卡上)
|
|
359
|
+
⇒ 给根留白只会露出**页面底**,比面套面更糟。
|
|
360
|
+
|
|
192
361
|
## 侧槽宽度:内容要用百分比时 [MUST] 用 `leftWidth` / `rightWidth`
|
|
193
362
|
|
|
194
363
|
### 🔴 为什么槽内的百分比宽会留下死白
|
|
@@ -43,6 +43,8 @@
|
|
|
43
43
|
(`repeat(auto-fill, minmax(Npx, 1fr))`,列数由容器宽自然得出,不需要断点表)。
|
|
44
44
|
- **`gap`:默认取间距阶梯的\*\*模块档\*\***(`APP_LAYOUT_GAP_CONFIG.size × 密度 × 1`,默认 8)。
|
|
45
45
|
`grid` 的 gap 是**卡与卡之间** = 模块档的定义值,[MUST NOT] 在消费侧写死像素补偿。
|
|
46
|
+
🔴 **与 `gridColumns` 正交**:不成网格(默认)时同样有纵向间距,见下「间距无条件存在」。
|
|
47
|
+
要贴合传 `:gap="0"`。
|
|
46
48
|
- **`card`:默认 `true`**(内置卡壳:border + radius + padding,全走 token)。
|
|
47
49
|
自带卡片视觉时传 `false` 关掉,[MUST NOT] 在自己的卡上再画一层边框叠上去。
|
|
48
50
|
- **`masonry`:默认 `false`**(瀑布流需要 JS 量高,按「需要 JS 就默认不开」的规则关着)。
|
|
@@ -83,6 +85,32 @@
|
|
|
83
85
|
**chunk 成等长的行**做虚拟化,而流体档的列数是浏览器算的、JS 拿不到 ⇒ chunk 无从下手。
|
|
84
86
|
这是实现约束不是遗漏,[MUST NOT] 为「对齐」把它硬塞进 `DataGridView`。
|
|
85
87
|
|
|
88
|
+
### 间距无条件存在(与网格正交)
|
|
89
|
+
|
|
90
|
+
**间距是卡片列表的固有属性,不是网格的附属品**(zc6ptn,甲方口径:
|
|
91
|
+
「无论是否多列展示、是否瀑布流,都不影响其 gap 的存在」)。
|
|
92
|
+
|
|
93
|
+
| 形态 | 间距由谁出 | 值 |
|
|
94
|
+
| --- | --- | --- |
|
|
95
|
+
| 成网格(`gridColumns` 任一形态) | 容器的 grid `gap` | `gap` |
|
|
96
|
+
| **不成网格**(默认) | **每项的 `margin-bottom`**(末项不下发) | 同一个 `gap` |
|
|
97
|
+
| 瀑布流(`masonry`) | 跨度里的 gap 分量(`ceil((卡高 + gap) / 行单位)`) | 同一个 `gap` |
|
|
98
|
+
|
|
99
|
+
三条路径**共用同一个值**,[MUST NOT] 另引第二个间距来源
|
|
100
|
+
(本仓已因此栽过:`--dc-core-content-gap` 与 gap 各随不同轴变动,
|
|
101
|
+
最松密度档出现「卡内 20 ≥ 外圈 20 > 卡间 8」的乱序,那个变量已被明令废掉)。
|
|
102
|
+
|
|
103
|
+
🔴 **不成网格时为何走 `margin` 而不是把容器改成 `flex` + `gap`**:
|
|
104
|
+
① 改 `display` 会连带改子项的布局语义(block → flex item),存量页面的可见变更面
|
|
105
|
+
远超「多出间距」;② `gap` 跨在盒**之间**、不计入 `clientHeight`,本仓在 `ViewLayout`
|
|
106
|
+
上栽过同一条(量不到 ⇒ 每页恒溢出一段)。
|
|
107
|
+
|
|
108
|
+
🔴 **末项不下发 margin**:块级流里末项的 `margin-bottom` 会与父盒底边折叠、**穿透出去**
|
|
109
|
+
—— 既量不到又推开后邻,与上面那条坑同形。故本组件只给「非末项」下发。
|
|
110
|
+
|
|
111
|
+
⚠️ 这是一次**可见变更**:此前不配 `gridColumns` 的页面是零间距。
|
|
112
|
+
「就是要贴着」的消费方 [MUST] 显式传 `:gap="0"`(阴性对照,出口有效)。
|
|
113
|
+
|
|
86
114
|
### 内置卡壳(`card`,默认开)
|
|
87
115
|
|
|
88
116
|
壳落在**已有的包裹层** `.data-list-view-item` 上(加 `is-card` 类),[MUST NOT] 另包一层:
|
|
@@ -92,6 +120,16 @@ DOM 层级恒定 ⇒ 消费方写的 `:deep()` 选择器不会随 prop 变;瀑
|
|
|
92
120
|
`.is-active` / `.is-selected` **仍是空钩子** —— 本族的立场从「[MUST NOT] 写死卡片视觉」
|
|
93
121
|
**收窄为**「[MUST NOT] 写死**状态**视觉」,两句话不再打架。
|
|
94
122
|
|
|
123
|
+
### 空态占位自己成卡(v0.32.0)
|
|
124
|
+
|
|
125
|
+
卡片态下容器**不铺面**(面与面不叠)。判据在**有项**时成立,**没有项时没有
|
|
126
|
+
「项自带的卡片」来接替** ⇒「暂无数据」直接浮在页面灰底上。
|
|
127
|
+
⇒ `.data-list-view-empty` **自己成卡**(面 / 圆角 / 内呼吸,**与卡壳同源**)。
|
|
128
|
+
|
|
129
|
+
ℹ️ **本组件不加 `max-width` 内缩**(`InfiniteListView` 那侧有):它的内缩由宿主
|
|
130
|
+
`TableMain` 的自持面 padding 给,而本组件**看不到那份 padding** ——
|
|
131
|
+
自己再加一层就是双重内缩,且无从判断该不该加。
|
|
132
|
+
|
|
95
133
|
### 瀑布流(`masonry`,默认关)
|
|
96
134
|
|
|
97
135
|
开启后走 `grid-auto-rows: <行单位>` + 每项 `grid-row-end: span N`(N 由实测卡高算),
|
|
@@ -121,7 +159,7 @@ DOM 层级恒定 ⇒ 消费方写的 `:deep()` 选择器不会随 prop 变;瀑
|
|
|
121
159
|
| `maxHeight` | `number` | `undefined` | 传入时容器 `overflowY: auto` 限高滚动 |
|
|
122
160
|
| `minHeight` | `number` | `undefined` | 传入时撑满至此高(配合 TableMain `fillHeight` 顶分页器到底) |
|
|
123
161
|
| `gridColumns` | `number \| Partial<Record<Breakpoint, number>> \| { min: number }` | `undefined` | 列数:数字 = 定列数;对象 = el-col span 制断点表(与 `DataGridView` 同语义);`{ min }` = 流体列宽 `repeat(auto-fill, minmax(Npx,1fr))`。不传 = 不成网格 |
|
|
124
|
-
| `gap` | `number` | 模块档(默认 `8`) | item 间距(px)。缺省取间距阶梯模块档,随 gap
|
|
162
|
+
| `gap` | `number` | 模块档(默认 `8`) | item 间距(px)。缺省取间距阶梯模块档,随 gap 基数与密度缩放。**与 `gridColumns` 正交**:不成网格时走每项 `margin-bottom`、同值 |
|
|
125
163
|
| `card` | `boolean` | `true` | 内置卡壳(border/radius/padding,走 token;落在 `.data-list-view-item` 上)。自带卡片视觉时关掉 |
|
|
126
164
|
| `masonry` | `boolean` | `false` | 瀑布流装箱(需要 JS 量高,故默认关)。顺序仍行优先 |
|
|
127
165
|
| `selectable` | `boolean` | `false` | 启用选中能力 |
|
|
@@ -176,6 +214,7 @@ DOM 层级恒定 ⇒ 消费方写的 `:deep()` 选择器不会随 prop 变;瀑
|
|
|
176
214
|
| `active` | `boolean` | `false` | 是否为「当前项」(active,与勾选无关)→ `.is-active` |
|
|
177
215
|
| `card` | `boolean` | `false` | 是否套内置卡壳 → `.is-card`(border/radius/padding 走 token)。由 `DataListView` 下发,默认值以它为准 |
|
|
178
216
|
| `spanRows` | `number` | `undefined` | 瀑布流跨度(`grid-row-end: span N`);仅 `masonry` 开启时由 `DataListView` 下发 |
|
|
217
|
+
| `flowGap` | `number` | `undefined` | **不成网格时的纵向间距**(`margin-bottom`);由 `DataListView` 按「非末项 且 不成网格」条件下发,成网格时恒 `0`(间距归 grid 的 `gap`,[MUST NOT] 叠加) |
|
|
179
218
|
|
|
180
219
|
### Emits / Expose
|
|
181
220
|
|
|
@@ -40,13 +40,72 @@
|
|
|
40
40
|
|
|
41
41
|
## 能力边界 / 按需使用
|
|
42
42
|
|
|
43
|
-
- **默认即够用:滚动触发 + 底部三态(加载/错误重试/到底)+
|
|
43
|
+
- **默认即够用:滚动触发 + 底部三态(加载/错误重试/到底)+ 虚拟化 + 内置卡壳全内置**——只传 `data` / `itemKey` / 状态 + 监听 `load-more` 即得无限滚动卡片列表。
|
|
44
|
+
- **`card`:默认 `true`**(内置卡壳:面 + 圆角 + 1px 边框 + 内呼吸,全走 token)。
|
|
45
|
+
自画卡片视觉时传 `false` 关掉,[MUST NOT] 在自己的卡上再画一层边框叠上去。
|
|
44
46
|
- `estimateSize`:默认 200px 预估行高,虚拟化按实际测量自动校准;项高差异大时可调小/调大优化滚动条精度。
|
|
45
47
|
- `maxHeight`:默认 `undefined`(自然高度,撑开父容器);限高滚动时传容器最大高(内部 `overflowY: auto`)。
|
|
46
48
|
- `pullRefresh`:默认关;开启后支持触摸下拉刷新(touch 三事件 + 顶部刷入指示器)→ 发 `refresh`。桌面 Web 常规用外部刷新按钮/自动刷新,[MUST NOT] 依赖手势。
|
|
47
49
|
- `#error` / `#end` / `#loading-more` 插槽可覆写底部各态默认渲染。
|
|
48
50
|
- `#empty`:`data` 为空时显示(默认 `<el-empty />`)。
|
|
49
51
|
|
|
52
|
+
## item 间距(`itemGap`,缺省 = 模块档)
|
|
53
|
+
|
|
54
|
+
**间距是列表的固有属性,不是某个形态的附属品**(zc6ptn)—— 故缺省值取间距阶梯的
|
|
55
|
+
**模块档**(`APP_LAYOUT_GAP_CONFIG.size × 密度 × 1`,默认 8),而不是 `0`。
|
|
56
|
+
解析走 data-view 族的 `useDataViewGap`,与 `DataListView` 的 `gap` **同一个函数**
|
|
57
|
+
⇒ 「同源同值」是构造保证,不是两处碰巧写了同一个表达式。
|
|
58
|
+
|
|
59
|
+
🔴 **[MUST] 透传给虚拟器(`gap`),[MUST NOT] 改用项自身的 `margin`**:
|
|
60
|
+
`measureElement` 量的是 borderBox、**吃不到 margin** ⇒ 总高会短一截、滚到底提前停。
|
|
61
|
+
(这与 `DataListView` 不成网格时走 margin 不矛盾:那条路径没有虚拟化、
|
|
62
|
+
父盒直接按块级流累高。)
|
|
63
|
+
|
|
64
|
+
⚠️ 这是一次**可见变更**:此前缺省是 `0`(贴在一起)。要贴合的消费方 [MUST] 显式传 `:item-gap="0"`。
|
|
65
|
+
|
|
66
|
+
ℹ️ `DataGridView` **不受影响** —— 它一直显式下发(非瀑布流传 `0`,行与行的间距由
|
|
67
|
+
每行自己的 `padding-bottom` 承担;瀑布流传 `gridGap`)。
|
|
68
|
+
|
|
69
|
+
## 内置卡壳(`card`,默认开)
|
|
70
|
+
|
|
71
|
+
上拉加载的三条路径此前**只有它没有卡壳**(`TableMain` 的 `customView` → `DataListView`、
|
|
72
|
+
`DataGridView` 都是 `hn3kzp` 那批做的、默认即开)。而本组件**在 core 顶层 export**、
|
|
73
|
+
app 也有独立范式页直接用它 ⇒ **缺口对下游可见**,不是「它只是 `DataGridView` 的内部引擎」。
|
|
74
|
+
|
|
75
|
+
壳落在每项外层的 `.infinite-list-view__row` 上(虚拟项容器,`measureElement` 量的是
|
|
76
|
+
borderBox ⇒ 壳的 padding / border **计进项高**,总高与落位自动正确)。
|
|
77
|
+
|
|
78
|
+
🔴 **取值与另两条路径同源**:面 / 圆角 / 边框取自共享 less mixin `card-shell.less`,
|
|
79
|
+
内呼吸取间距阶梯**呼吸档**(`useDataViewGap().cardPad`)。
|
|
80
|
+
[MUST NOT] 另写一套 —— 本仓已因「第二来源」栽过(`--dc-core-content-gap` 被明令废掉,
|
|
81
|
+
它与 gap 各随不同轴变动,最松密度档出现「卡内 20 ≥ 外圈 20 > 卡间 8」的乱序)。
|
|
82
|
+
|
|
83
|
+
⚠️ **这是一次可见变更**:自画卡片的下游会**多出一层边框**。出口 = `:card="false"`。
|
|
84
|
+
|
|
85
|
+
ℹ️ `DataGridView` **不受影响**:它的卡壳落在自己的 `__cell` 上,
|
|
86
|
+
内层本组件由它显式传 `:card="false"`(否则整行会被再套一层壳)。
|
|
87
|
+
|
|
88
|
+
## 占位块自己成卡(空 / 加载 / 错误)
|
|
89
|
+
|
|
90
|
+
卡片态下容器**不铺面**(`itemCard` ⇒ 面与面不叠)。这条判据在**有项**时成立,
|
|
91
|
+
**没有项时没有「项自带的卡片」来接替,面的责任无人接** ——
|
|
92
|
+
于是「暂无数据」直接浮在页面灰底上,整块区域没有任何面。
|
|
93
|
+
|
|
94
|
+
⇒ 空 / 加载 / 错误三态共用的 `.infinite-list-view__empty` **自己成卡**
|
|
95
|
+
(面 / 圆角 / 内呼吸,**与卡壳同源**)。**占位块在视觉上扮演的正是那张缺席的卡**。
|
|
96
|
+
(无数据时的错误 + 重试也走 `#empty` 槽 ⇒ 一处修覆盖三态。)
|
|
97
|
+
|
|
98
|
+
🔴 **[MUST NOT] 改走「空态时把容器的面开回来」**:那会让数据由空变非空时
|
|
99
|
+
**面闪一下消失**,是新引入的问题;且「项自带卡片 ⇒ 容器不铺面」这条判据本身是对的,
|
|
100
|
+
不该为空态把它改成跟数据走。
|
|
101
|
+
|
|
102
|
+
**最大宽度**:`max-width: calc(100% - 模块档 × 2)`,**仅在 `surfacePad === 0` 时生效**
|
|
103
|
+
(`surface` 关档,如置于 `ModalConfirm` 正文)—— `surface` 开时容器已有呼吸档内缩,
|
|
104
|
+
再加就是双重内缩。
|
|
105
|
+
|
|
106
|
+
ℹ️ **底部三态条(加载更多 / 错误重试 / 到底)不套卡**:它们出现在**已有卡片之下**,
|
|
107
|
+
是尾随的状态行,不是「缺席的那张卡」的替身。
|
|
108
|
+
|
|
50
109
|
## 自持面(`surface`)
|
|
51
110
|
|
|
52
111
|
本组件**自己持有那块面**(面色 `--el-bg-color` + 内呼吸 + 圆角),不依赖外层容器
|
|
@@ -82,6 +141,10 @@
|
|
|
82
141
|
| `overscan` | `number` | `5` | 视口外预渲染项数(防快速滚动白屏) |
|
|
83
142
|
| `maxHeight` | `number` | `undefined` | 传入时容器限高滚动(内部 `overflowY: auto`) |
|
|
84
143
|
| `pullRefresh` | `boolean` | `false` | opt-in 触摸下拉刷新(默认关;开启后 touch 手势触发 `refresh`) |
|
|
144
|
+
| `card` | `boolean` | **`true`** | 内置卡壳(落在 `.infinite-list-view__row` 上)。与另两条卡片路径**同一份取值** |
|
|
145
|
+
| `lanes` | `number` | `1` | 虚拟化列数(>1 即**瀑布流装箱**,由 virtual-core 的 `lanes` 算列位与 y) |
|
|
146
|
+
| `laneGap` | `number` | `0` | 多列时的**列间距**(px,横向);纵向间距走 `itemGap` |
|
|
147
|
+
| `itemGap` | `number` | **模块档(默认 `8`)** | 同列相邻项的**纵向间距**(px)。缺省取间距阶梯模块档,与 `DataListView` 的 `gap` **同一个解析口**(`useDataViewGap`)。透传 virtual-core 的 `gap` ⇒ 总高与位置都正确。要贴合传 `0` |
|
|
85
148
|
|
|
86
149
|
### Emits
|
|
87
150
|
|
|
@@ -122,9 +185,10 @@
|
|
|
122
185
|
```
|
|
123
186
|
|
|
124
187
|
- 判据 `itemCard`:`TableMain` 缺省跟随 **`customView`**(该态下内层 `DataListView` 的 `card`
|
|
125
|
-
默认开)、`DataGridView` 缺省跟随 **`card
|
|
126
|
-
|
|
127
|
-
|
|
188
|
+
默认开)、`DataGridView` 缺省跟随 **`card`**、**`InfiniteListView` 自 v0.32.0 起也跟随 `card`**。
|
|
189
|
+
- ⚠️ **它此前缺省是 `false`**,理由是「本组件没有内置卡壳、core 无从判断」——
|
|
190
|
+
`j8pwer` 把卡壳补上之后**那个理由消失了**,缺省 [MUST] 跟着改,
|
|
191
|
+
否则出现「有卡壳 + 容器仍铺面」的面套面(正是 `p4wrtn` 刚修掉的那个)。
|
|
128
192
|
- 🔴 **撤色不撤呼吸**:呼吸计入高度账(`surfacePad` 与可用高扣减同源),
|
|
129
193
|
一并撤会连带改 refine 的 reserve、整页溢出。
|
|
130
194
|
- 阴性:`card: false` / `itemCard: false` 时容器**照常出面**(别把非卡片态的面一起干掉)。
|
|
@@ -44,16 +44,20 @@ bridge.badge.set("/order/list", { kind: "new" });
|
|
|
44
44
|
|
|
45
45
|
代价是绝对定位不占位 → 角标必然向右**逃逸出宿主边界**,逃逸量 = `角标宽 − 13px`(EP 的 10px 内嵌已归零,另留 2px 让位;文字距按钮右缘 15px padding):
|
|
46
46
|
|
|
47
|
-
| 内置标 | 宽 | 逃逸 | 后果 |
|
|
48
|
-
| --- | --- | --- | --- |
|
|
49
|
-
|
|
|
50
|
-
|
|
|
51
|
-
| 开发中 / 规划中 / 待下线 /
|
|
47
|
+
| 内置标 | 字数 | 宽 | 逃逸 | 后果 |
|
|
48
|
+
| --- | --- | --- | --- | --- |
|
|
49
|
+
| **新** | 1 | 26px | 13px | 基本不碰邻居 |
|
|
50
|
+
| **更新 / 内测** | 2 | 38px | 25px | 一般不碰邻居 |
|
|
51
|
+
| 开发中 / 规划中 / 待下线 / 未开通 | 3 | 50px | 37px | 右缘可能顶到水平相邻宿主 |
|
|
52
52
|
|
|
53
53
|
⚠️ **原「内置标文案 [MUST] ≤2 个汉字」那条约束已作废**(甲方 2026-09-19 明示「不用关心太长」)。
|
|
54
54
|
逃逸量最终由消费方的布局间距决定,core [MUST NOT] 声称能保证零重叠;文案长度的后果由布局承担。
|
|
55
55
|
[MUST NOT] 因为这张表回推「所以该用图标 / 该截断」—— 见下文「内置档一律文字」。
|
|
56
56
|
|
|
57
|
+
⚠️ **那条作废管的是「别拿宽度回推去换方案」,不是「文案可以随便改长」**(v0.32.0,b9tmkc):
|
|
58
|
+
**资讯三档回短是因为它们压根没被要求改过**(撤回图标那批把悬浮气泡的 `label` 当正文搬了回来),
|
|
59
|
+
逃逸量降回去只是**顺带**。状态四档三字**照旧合法**。
|
|
60
|
+
|
|
57
61
|
### 尺寸:固定 12px / 18px,不随 density 变
|
|
58
62
|
|
|
59
63
|
| 项 | 值 | 来源 |
|
|
@@ -109,9 +113,9 @@ bridge.badge.set("/order/list", { kind: "new" });
|
|
|
109
113
|
| kind | 文案 | 语义色 | 为什么 |
|
|
110
114
|
| --- | --- | --- | --- |
|
|
111
115
|
| `count` | **数字** | `danger` 红 | 待办数量要人行动,未读红点是全行业最强共识 |
|
|
112
|
-
| `new` |
|
|
113
|
-
| `updated` |
|
|
114
|
-
| `beta` |
|
|
116
|
+
| `new` | 新 | `success` 绿 | 正面资讯。[MUST NOT] 复用红——会与 `count` 撞色 |
|
|
117
|
+
| `updated` | 更新 | `primary` 主色 | 中性被动通知,不喧宾夺主 |
|
|
118
|
+
| `beta` | 内测 | `warning` 橙 | 能用但不稳定需谨慎 |
|
|
115
119
|
| `wip` | 开发中 | `info` 灰 | 尚不完善,中性、不引导点击。**仅提示,不拦点击** |
|
|
116
120
|
| `planned` | 规划中 | `info` 灰 | 还没开工,比 `wip` 更靠前。**不进遮挡档** |
|
|
117
121
|
| `deprecated` | 待下线 | `danger` 红 | 「要迁走」需要用户采取行动 |
|
|
@@ -134,9 +138,13 @@ bridge.badge.set("/order/list", { kind: "new" });
|
|
|
134
138
|
|
|
135
139
|
| 版本 | 资讯三档 `new`/`updated`/`beta` | 状态四档 `wip`/`planned`/`deprecated`/`locked` |
|
|
136
140
|
| --- | --- | --- |
|
|
137
|
-
| ≤ v0.29 |
|
|
141
|
+
| ≤ v0.29 | 文字(新 / 更新 / 内测) | 图标 |
|
|
138
142
|
| v0.30 | 图标 | 图标 |
|
|
139
|
-
|
|
|
143
|
+
| v0.31.0 | 文字,但**文案被夹带改长**(新上线 / 已更新 / 内测中) | 文字 |
|
|
144
|
+
| **v0.32.0** | **文字,文案回正(新 / 更新 / 内测)** | 文字(不动) |
|
|
145
|
+
|
|
146
|
+
⚠️ **形态本身在传达分类**:资讯档短(1–2 字)、状态档三字 ——
|
|
147
|
+
v0.31.0 那一版七档全三字,扫视时分不出两类。
|
|
140
148
|
|
|
141
149
|
图标是**全族退场**:`ElIcon` / `ElTooltip` / 预设的 `icon` 与 `iconScale` 字段一并删除。
|
|
142
150
|
悬浮气泡随之去掉 —— 它当初存在只为「语义随文字消失后补回来」,文字回来了它就是重复。
|
|
@@ -41,8 +41,34 @@ const submit = async () => {
|
|
|
41
41
|
- 具名槽 `#<config.key>`:默认关(单项由配置 render / props 驱动);仅当单一项需要完全自定义渲染(复杂组合控件)才开。
|
|
42
42
|
- `#default` 整体接管栅格:默认关、少用;仅当整个栅格结构需重构时开。
|
|
43
43
|
- `layoutByContainer`:默认关(按 window 媒体查询);仅当表单落入窄容器(侧栏 / 抽屉内嵌)且视口响应式挤崩时才开。
|
|
44
|
+
- `labelHide`(单项):默认关;标签不显示也不占位、控件顶满整行。**不分是否给 `labelWidth`**(见下)。
|
|
44
45
|
- **完整能力演示**(新增 / 编辑双模式三方法编排 + 校验提交):`apps/reference/src/pages/form/guide/`——能力展示,非推荐默认。
|
|
45
46
|
|
|
47
|
+
## `labelHide` —— 两种 label DOM 形态都要藏
|
|
48
|
+
|
|
49
|
+
EP 的 label **有两种结构**,取决于 `label-width`:
|
|
50
|
+
|
|
51
|
+
| `label-width` | DOM | 谁落在这一半 |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| `auto` | `.el-form-item__label-wrap` > `.el-form-item__label` | `FormSearch` / `FormSubmitPanel`(各自默认了 `auto`) |
|
|
54
|
+
| 其余(含**不给**) | 只有 `.el-form-item__label` | **裸 `FormMain`** |
|
|
55
|
+
|
|
56
|
+
🔴 **v0.32.0 之前只藏了 wrap** ⇒ 裸 `FormMain` 下 `labelHide` **静默失效**:
|
|
57
|
+
`form-item-label-hide` 这个类确确实实挂在 DOM 上、devtools 里一切正常,
|
|
58
|
+
消费方的 `vue-tsc` / `eslint` / `vite build` / 单测全绿 —— 只是那条 CSS 规则匹配不到任何元素
|
|
59
|
+
(消费方 qd-ai-aigc 实测四个 label 各占 40–51px,把控件挤窄;ncl4rj)。现已两条都藏。
|
|
60
|
+
|
|
61
|
+
🔴 **[MUST NOT] 改成「给 `FormMain` 也默认 `labelWidth: auto`」**:那会改掉**所有**裸
|
|
62
|
+
`FormMain` 的标签对齐方式,可见变更面比 `labelHide` 自己大得多。
|
|
63
|
+
|
|
64
|
+
⚠️ **仍只在 `label` 有值时生效** —— 无 `label` 时 EP 会给 content 加 `margin-left` 留白,
|
|
65
|
+
那一档要改用 `labelWidth: 0`。
|
|
66
|
+
|
|
67
|
+
⚠️ **加用例时断言 [MUST] 落在渲染结果上**(label 是否占位 / 宽是否为 0),
|
|
68
|
+
[MUST NOT] 只断类名在不在 —— 本现象的全部症状就是「类名在、规则不命中」,
|
|
69
|
+
断类名的用例在出 bug 时也是全绿的。且样例里 [MUST] 有一条**裸 `FormMain`**。
|
|
70
|
+
范式页:`apps/reference/src/pages/form/label-hide/`(裸用 / `auto` / 阴性三栏对照)。
|
|
71
|
+
|
|
46
72
|
## API
|
|
47
73
|
> ⚠️ API 以 types.ts 与组件源码为真相源;与文档冲突时以源码为准。
|
|
48
74
|
|
|
@@ -122,6 +122,16 @@ padding 与内部分段档),[MUST NOT] 退回「量内部两段再拼」。
|
|
|
122
122
|
|
|
123
123
|
标题行**露底不成面**(两卡模型里 header 不是卡),锚点类 `.dc-list-layout__header`。
|
|
124
124
|
|
|
125
|
+
**scope 带 `title`**(v0.32.0 补,与 `ViewLayout` 对齐):插槽接管后仍拿得到原标题
|
|
126
|
+
⇒ 「加个徽标 / 加个副标题」这类小改不必把 `title` 再从外面透一遍。
|
|
127
|
+
|
|
128
|
+
```vue
|
|
129
|
+
<template #header="{ title }">{{ title }} <ElTag>草稿</ElTag></template>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
⚠️ 它是**内容区的标题行**,不是页面 chrome。要页面级 navbar(返回 / ⋮ / tabbar)
|
|
133
|
+
[MUST] 走 `AppPage` 的 `showNavBar`,[MUST NOT] 拿本槽拼 —— 同名不同物。
|
|
134
|
+
|
|
125
135
|
## API
|
|
126
136
|
> ⚠️ API 以 types.ts 与组件源码为真相源;与文档冲突时以源码为准。
|
|
127
137
|
|
|
@@ -174,7 +184,8 @@ padding 与内部分段档),[MUST NOT] 退回「量内部两段再拼」。
|
|
|
174
184
|
|
|
175
185
|
| 槽 | scope | 语义 |
|
|
176
186
|
| --- | --- | --- |
|
|
177
|
-
| `#header`
|
|
187
|
+
| `#header` | `{ title }` | 标题行(插槽 > `title` > 不渲染)。**scope 带 `title`**(v0.32.0 补) |
|
|
188
|
+
| `#operation` | 无 | 搜索区下方扩展(操作条) |
|
|
178
189
|
| `#custom-view-item` | `DataListViewItemScope<T>` | customView 模式单项卡片渲染 |
|
|
179
190
|
| `#form-<key>` | `FormScope` | 覆盖搜索表单单项 |
|
|
180
191
|
| `#table-<prop>` | `TableColumnDefaultScope<T, ListLayoutInnerInjectInfo<PO,F>>` | 覆盖列单元格 |
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
## 菜单项徽标
|
|
24
24
|
|
|
25
|
-
两种形态下,凡渲染出路由 `path` 的位置(叶子项 / ElSubMenu 标题 / 分组标题)都会按 **`path` 作 key** 查 `bridge.badge` 注册表,命中则渲染绝对定位角标(数量 /
|
|
25
|
+
两种形态下,凡渲染出路由 `path` 的位置(叶子项 / ElSubMenu 标题 / 分组标题)都会按 **`path` 作 key** 查 `bridge.badge` 注册表,命中则渲染绝对定位角标(数量 / 新 / 更新 / 内测 / 开发中 / 自定义),**不压字、不改变宿主尺寸**;未命中零影响。
|
|
26
26
|
|
|
27
27
|
无需在菜单数据里另配 key。完整契约见 [bridge 文档 · 徽标注册表](../../bridge/docs/README.md)。
|
|
28
28
|
|