descriptions —— 描述列表
This content is not available in your language yet.
描述列表是「唯讀的表格」:展示一筆記錄的若干欄位(標籤 + 值),不需要排序、篩選、分頁。它的難點很集中——條目佔據多列時的換行計算:某個條目 span: 2,但本列只剩 1 行寬,怎麼辦?末列只有 2 個條目但共 4 行,要不要補位?buildDescriptionRows 就是在回答這些問題。
- 各端實作
LhDescriptions:詳情頁(訂單詳情、使用者資料)、設定摘要、審批流資訊展示。 - 唯讀的「標籤-值」成組展示,且需要每列容納多個欄位。
- 不該用它:需要排序/篩選/列操作的表格(用
table);單欄位展示(直接 label + 文字即可);需要編輯(用form)。
import { getDescriptionsClassNames, buildDescriptionRows,} from '@lh-ui/share/core/descriptions'import type { LhDescriptionsItem, LhDescriptionsState } from '@lh-ui/share/core/descriptions'buildDescriptionRows 的四條規則都是防禦性的,每條對應一類真實輸入:
- 非法 span 兜底為 1:
span <= 0、NaN、非數字(Number('寬')= NaN)一律按 1 處理。設定常來自使用者傳的 props,髒值不該讓版面崩成 0 行。 - 超本列剩餘寬度鉗制:
used + span > column時鉗到剩餘寬度(至少 1 行)。若直接換列,當前列會留下一個空洞,視覺上像 bug。 - 單條 span 超整列鉗到整列:
column: 3時傳span: 5的條目佔滿整列,而不是溢出。 - 末列補位:最後一列不足
column時,filler欄位告知渲染層要補幾個佔位儲存格——帶邊框樣式下不補位會缺一條邊框。
傳回值是「列的陣列」,每列含 cells(條目 + 實際 span)和 filler(要補的佔位數)。UI 層只需兩層 v-for。
| 函式 | 簽名 | 傳回 | 作用 |
|---|---|---|---|
getDescriptionsClassNames |
(state: LhDescriptionsState) => string[] |
類別名 | border 修飾 |
buildDescriptionRows |
(items: LhDescriptionsItem[], column: number) => Row[] |
列結構 | 換列 + 補位 |
type Row = { cells: { item: LhDescriptionsItem; span: number }[] filler: number}export interface LhDescriptionsItem { label: string value?: string | number // 也可用作用域插槽傳入 span?: number // 佔據行數,預設 1,超出 column 會被鉗制}
export interface LhDescriptionsState { column: number // 每列展示的行數 border: boolean // 是否展示邊框(表格版面配置)}descriptions 是展示性元件,沒有 APG 角色要求。推薦的 DOM 結構是定義列表語義:
<dl> <dt>用户名</dt><dd>lhgb</dd> <dt>邮箱</dt><dd>i@lhgb.top</dd></dl>這與「標籤-值」的資料模型天然對應,讀屏軟體能正確播報「使用者名稱:lhgb」。若用 <table> 實作(帶邊框樣式時常見),加 role="presentation" 或保留表頭語義——不要用真正的 <th scope="row"> 又不給 summary,那會讓讀屏軟體以為這是個可互動表格。
帶邊框時 filler 補位的佔位儲存格應加 aria-hidden="true",避免讀屏軟體播報空儲存格。
import { buildDescriptionRows } from '@lh-ui/share/core/descriptions'
// column 3:第三個條目 span 2,但本行只剩 1 列寬 → 鉗到 1buildDescriptionRows([ { label: '用户名', value: 'lhgb' }, { label: '邮箱', value: 'i@lhgb.top' }, { label: '签名', value: '写代码的', span: 2 },], 3)// [{ cells: [使用者名(1), 電子郵件信箱(1), 簽名(1)], filler: 0 }] ← 鉗制後恰好滿行
// 注意:實作是**鉗制到剩餘寬度**而非換行——span 放不進本行時不會頂到下一行buildDescriptionRows([ { label: '用户名', value: 'lhgb' }, { label: '签名', value: '写代码的', span: 2 }, { label: '邮箱', value: 'i@lhgb.top' },], 2)// [// { cells: [使用者名(1), 簽名(2→1 鉗制)], filler: 0 }, ← 滿行// { cells: [電子郵件信箱(1)], filler: 1 }, ← 末行補 1 個佔位// ]
// 單條 span 超過整行列數:同樣被鉗到剩餘寬度(此處即整行)buildDescriptionRows([{ label: 'A', span: 1 }, { label: 'B', span: 5 }], 2)// [{ cells: [A(1), B(5→1 鉗制)], filler: 0 }] ← B 放進第一行剩餘的 1 列
// 只有 B 一條、且 span 超過整行時才佔滿整行buildDescriptionRows([{ label: 'B', span: 5 }], 2)// [{ cells: [B(5→2 鉗制)], filler: 0 }]
// 非法 span 兜底buildDescriptionRows([{ label: 'A', span: 0 }, { label: 'B', span: NaN }, { label: 'C', span: -1 }], 3)// [{ cells: [A(span 1), B(span 1), C(span 1)], filler: 0 }]<!-- Vue3 --><div :class="getDescriptionsClassNames({ column, border })"> <div v-for="(row, ri) in rows" :key="ri" class="lh-descriptions__row"> <template v-for="(cell, ci) in row.cells" :key="ci"> <div class="lh-descriptions__label" :style="{ gridColumn: `span ${cell.span}` }"> {{ cell.item.label }} </div> <div class="lh-descriptions__value" :style="{ gridColumn: `span ${cell.span}` }"> <slot :name="cell.item.label" :item="cell.item">{{ cell.item.value }}</slot> </div> </template> <div v-for="f in row.filler" :key="`filler-${f}`" class="lh-descriptions__filler" aria-hidden="true" /> </div></div>const rows = computed(() => buildDescriptionRows(props.items, props.column))// React:用 CSS grid 的 gridColumn: `span ${cell.span}`;// 注意 label 與 value 各佔 span 列,所以「column 3」實際是 6 個網格單元// uniapp:<view> + flex 比例(span / column * 100%);// 帶 border 時 flex 佈局的邊框需要用偽元素或 box-shadow 模擬表格線| 類別名 | 語義 |
|---|---|
.lh-descriptions |
基礎類 |
.lh-descriptions--border |
帶邊框(標籤底色區分) |
.lh-descriptions__row |
一列 |
.lh-descriptions__label |
標籤格 |
.lh-descriptions__value |
值格 |
.lh-descriptions__filler |
末列佔位(aria-hidden) |
標籤寬度的兩種模式:border 下標籤與值同列等寬;無邊框時標籤寬度由內容決定(--lh-descriptions-label-width 可覆蓋)。標籤文字 --lh-text-color-secondary,值 --lh-text-color-primary。
- column 與網格單元的關係:
span是「條目數」單位,但渲染時標籤和值各佔一份寬度。用 CSS grid 時若把 label/value 各當一個網格單元,column: 3實際需要 6 行網格——UI 層的行數定義要與 core 的column口徑一致(一個條目 = 一個 span 單位)。 - 響應式 column:窄螢幕把
column調小(如 3 → 1),buildDescriptionRows重算即可。core 不監聽螢幕寬度,UI 層用媒體查詢或容器查詢切換。 - 作用域插槽的 key:UI 層通常用
item.label作插槽名,標籤含特殊字元(空格、中文)時框架相容性 OK,但含/或重複標籤會衝突——建議 UI 層提供slot欄位別名(本型暫未提供,各端可自行擴充)。 filler只在 border 模式下必需:無邊框時補位儲存格不可見,但保留它們不佔額外渲染成本,統一渲染更簡單。- 空 items:
buildDescriptionRows([], 3)傳回[],UI 層渲染空容器——記得給空態(empty元件或提示文案)。 - 值的預設顯示:
value為 undefined 時顯示什麼由 UI 層定(通常—),core 不插手文案。
@lh-ui/share/core/descriptions → buildDescriptionRows( )返回值
(填好参数后点运行)Copyright © 2024-2026 FengMo WenXue