Element Descriptions 描述列表组件实战指南:用法、API 与源码级布局原理
2026/9/19 14:27:36 网站建设 项目流程

Element Descriptions 描述列表组件实战指南:用法、API 与源码级布局原理

【免费下载链接】elementA Vue.js 2.0 UI Toolkit for Web项目地址: https://gitcode.com/gh_mirrors/eleme/element

导读

el-descriptions是 Element(Element UI)中用于"列表形式展示多个字段"的布局组件,适合详情页、用户信息展示、订单核对等只读信息场景。本文以 Element 仓库中的官方文档 examples/docs/zh-CN/descriptions.md 为骨架,完整覆盖基础用法、尺寸控制、垂直布局、自定义样式与全部 API,并结合 packages/descriptions 下的源码实现,为你讲清楚column栅格算法、span合并规则、冒号渲染等底层原理。读完本文,你可以直接照抄示例落地一个详情列表,也能理解组件内部是如何把一组 Item 组装成表格的。


一、组件定位与引入方式

Descriptions 属于 Element 的标准表单展示类组件,在仓库中的代码组织为:

  • 组件源码:packages/descriptions/src/index.js(ElDescriptions主组件)
  • 条目源码:packages/descriptions/src/descriptions-item.js(ElDescriptionsItem
  • 行渲染源码:packages/descriptions/src/descriptions-row.js(ElDescriptionsRow
  • 注册入口:packages/descriptions/index.js
  • 类型声明:types/descriptions.d.ts 与 types/descriptions-item.d.ts

使用上只需引入两个标签:外层el-descriptions负责整体布局(标题、边框、列数、方向、尺寸),内层el-descriptions-item负责单个字段(标签与内容)。它本质上是把若干 Item 渲染成一张table,因此天然支持列对齐与跨列合并。


二、基础用法

最简单的用法是为每个el-descriptions-item设置label作为字段名,把字段值写在标签内:

<el-descriptions title="用户信息"> <el-descriptions-item label="用户名">kooriookami</el-descriptions-item> <el-descriptions-item label="手机号">18100000000</el-descriptions-item> <el-descriptions-item label="居住地">苏州市</el-descriptions-item> <el-descriptions-item label="备注"> <el-tag size="small">学校</el-tag> </el-descriptions-item> <el-descriptions-item label="联系地址">江苏省苏州市吴中区吴中大道 1188 号</el-descriptions-item> </el-descriptions>

要点说明:

  • title显示在列表左上方,默认不渲染任何元素;只有传入titleextra或对应插槽时,头部才会出现(见 源码 的render判断)。
  • 内容区是默认插槽,可以放任意内容,例如示例中的el-tag,也可以放图片、链接等富内容。
  • 未设置border时默认无边框,采用"标签 + 冒号 + 内容"的紧凑排版。

三、不同尺寸:size 与全局默认值

Descriptions 支持medium / small / mini三种尺寸(默认继承全局配置),可以用一个单选组动态切换:

<template> <el-radio-group v-model="size"> <el-radio label="">默认</el-radio> <el-radio label="medium">中等</el-radio> <el-radio label="small">小型</el-radio> <el-radio label="mini">超小</el-radio> </el-radio-group> <el-descriptions class="margin-top" title="带边框列表" :column="3" :size="size" border> <template slot="extra"> <el-button type="primary" size="small">操作</el-button> </template> <el-descriptions-item> <template slot="label"> <i class="el-icon-user"></i> 用户名 </template> kooriookami </el-descriptions-item> <el-descriptions-item> <template slot="label"> <i class="el-icon-mobile-phone"></i> 手机号 </template> 18100000000 </el-descriptions-item> <el-descriptions-item> <template slot="label"> <i class="el-icon-location-outline"></i> 居住地 </template> 苏州市 </el-descriptions-item> <el-descriptions-item> <template slot="label"> <i class="el-icon-tickets"></i> 备注 </template> <el-tag size="small">学校</el-tag> </el-descriptions-item> <el-descriptions-item> <template slot="label"> <i class="el-icon-office-building"></i> 联系地址 </template> 江苏省苏州市吴中区吴中大道 1188 号 </el-descriptions-item> </el-descriptions> <el-descriptions class="margin-top" title="无边框列表" :column="3" :size="size"> <template slot="extra"> <el-button type="primary" size="small">操作</el-button> </template> <el-descriptions-item label="用户名">kooriookami</el-descriptions-item> <el-descriptions-item label="手机号">18100000000</el-descriptions-item> <el-descriptions-item label="居住地">苏州市</el-descriptions-item> <el-descriptions-item label="备注"> <el-tag size="small">学校</el-tag> </el-descriptions-item> <el-descriptions-item label="联系地址">江苏省苏州市吴中区吴中大道 1188 号</el-descriptions-item> </el-descriptions> </template> <script> export default { data () { return { size: '' }; } } </script>

值得注意的实现细节(见 源码):

descriptionsSize() { return this.size || (this.$ELEMENT || {}).size; }

即:当未显式传入size时,组件会回退读取全局配置$ELEMENT.size。这与 Element 的 Button、Input 等组件的尺寸约定一致,便于整个项目统一控制密度。尺寸最终以el-descriptions--medium/small/mini类名作用到表格上,对应的内边距与字号定义在 packages/theme-chalk/src/descriptions.scss:

尺寸带边框内边距无边框下边距字号
默认12px 10px12px基础字号
medium10px10px基础字号
small8px 10px8px12px
mini6px 10px6px12px

本示例同时演示了slot="extra"插槽:它显示在右上角,可放置按钮等操作区;此外示例中用template slot="label"配合el-icon-*图标实现了带图标的标签,这说明label插槽优先级高于label属性。


四、垂直列表:direction="vertical"

默认direction="horizontal"是"标签在左、内容在右"的横排;设置为vertical后,标签与内容各自独占一行,形成上下结构的列表:

<el-descriptions title="垂直带边框列表" direction="vertical" :column="4" border> <el-descriptions-item label="用户名">kooriookami</el-descriptions-item> <el-descriptions-item label="手机号">18100000000</el-descriptions-item> <el-descriptions-item label="居住地" :span="2">苏州市</el-descriptions-item> <el-descriptions-item label="备注"> <el-tag size="small">学校</el-tag> </el-descriptions-item> <el-descriptions-item label="联系地址">江苏省苏州市吴中区吴中大道 1188 号</el-descriptions-item> </el-descriptions> <el-descriptions class="margin-top" title="垂直无边框列表" :column="4" direction="vertical"> <el-descriptions-item label="用户名">kooriookami</el-descriptions-item> <el-descriptions-item label="手机号">18100000000</el-descriptions-item> <el-descriptions-item label="居住地" :span="2">苏州市</el-descriptions-item> <el-descriptions-item label="备注"> <el-tag size="small">学校</el-tag> </el-descriptions-item> <el-descriptions-item label="联系地址">江苏省苏州市吴中区吴中大道 1188 号</el-descriptions-item> </el-descriptions>

上例中:span="2"让"居住地"在column="4"下横向占用两列宽度。从行渲染源码(descriptions-row.js)可以看到,垂直模式下每个 Item 被渲染为两行:

  1. 第一行<tr>内放若干<th class="el-descriptions-item__label">colSpan等于该 Item 的span
  2. 第二行<tr>内放对应的<td class="el-descriptions-item__content">,同样按span设置colSpan

这也是为什么垂直列表在视觉上是"标签一行、内容一行"的原因。官方单元测试 test/unit/specs/descriptions.spec.js 对两种方向做了断言:水平模式下每行子节点数是column × 2(标签 + 内容),切换为垂直后每行子节点数等于column,且上下两行对应单元格内容一致。


五、自定义样式:类名、内联样式与样式覆盖

Descriptions 允许在组件级条目级分别自定义标签和内容的类名与内联样式:

<el-descriptions title="自定义样式列表" :column="3" border> <el-descriptions-item label="用户名" label-class-name="my-label" content-class-name="my-content">kooriookami</el-descriptions-item> <el-descriptions-item label="手机号">18100000000</el-descriptions-item> <el-descriptions-item label="居住地">苏州市</el-descriptions-item> <el-descriptions-item label="备注"> <el-tag size="small">学校</el-tag> </el-descriptions-item> <el-descriptions-item label="联系地址" :contentStyle="{'text-align': 'right'}">江苏省苏州市吴中区吴中大道 1188 号</el-descriptions-item> </el-descriptions> <style> .my-label { background: #E1F3D8; } .my-content { background: #FDE2E2; } </style>

使用建议与实现要点:

  • label-class-name/content-class-name会被拼接到th/tdclass上,配合普通 CSS 即可定制背景色、字体等;
  • :contentStyle传入对象作为内联样式(示例中让"联系地址"内容右对齐);
  • 在 DOM 模板(非构建环境)中应使用 kebab-case 形式label-class-namecontent-style等;在 SFC 模板中两种写法均有效;
  • 条目级样式会覆盖组件级同名配置。源码中 descriptions-row.js 对labelClassName / contentClassName / labelStyle / contentStyle四个属性做了合并:res[key] = item.props[key] || elDescriptions[key],即 Item 有值用 Item 的,否则回退到el-descriptions上的值;
  • 标签单元格还内置了.is-bordered-label样式:带边框时标签背景为浅灰、字体加粗(见 descriptions-item.scss)。

另外,模板示例中直接使用:contentStyle是组件内部 props 的 camelCase 写法,与types/descriptions.d.ts中声明的labelStyle: objectcontentStyle: object保持一致。


六、完整 API 一览

Descriptions Attributes

参数说明类型可选值默认值
border是否带有边框booleanfalse
column一行Descriptions Item的数量number3
direction排列的方向stringvertical / horizontalhorizontal
size列表的尺寸stringmedium / small / mini
title标题文本,显示在左上方string
extra操作区文本,显示在右上方string
colon是否显示冒号booleantrue
labelClassName自定义标签类名string
contentClassName自定义内容类名string
labelStyle自定义标签样式object
contentStyle自定义内容样式object

Descriptions Slots

Name说明
title自定义标题,显示在左上方
extra自定义操作区,显示在右上方

Descriptions Item Attributes

参数说明类型可选值默认值
label标签文本string
span列的数量number1
labelClassName自定义标签类名string
contentClassName自定义内容类名string
labelStyle自定义标签样式object
contentStyle自定义内容样式object

Descriptions Item Slots

Name说明
label自定义标签文本

七、源码原理:column 栅格算法与三种渲染分支

了解 API 之后,再看组件内部如何工作。ElDescriptionsItem本身是不渲染任何 DOM 的"配置节点"——它的render()直接返回null(见 descriptions-item.js),只承载label / span等 props。真正把数据变成表格的是主组件的getRows()与行组件ElDescriptionsRow

1.getRows()的栅格算法

见 index.js。核心逻辑:

  • 从默认插槽中筛选出name === 'ElDescriptionsItem'的 vnode 作为数据源;
  • 通过getOptionProps读取每个 Item 的 props(含默认值),通过getSlots收集label与默认插槽内容;
  • 用计数器count = this.column模拟"每行还能放多少列":
    • span < count:当前 Item 放进本行,count -= span
    • span >= count:当前 Item 用filledNode补齐(若span > count钳制为 count),本行封口,count重置为column
    • 最后一项无论 span 多少,都会被强制设置为整行剩余宽度(filledNode(..., isLast = true)node.props.span = count),保证最后一行表格完整、不会出现空单元格。

2. 三种渲染分支

ElDescriptionsRow根据directionborder组合出三种结构(descriptions-row.js):

场景DOM 结构说明
direction="vertical"标签<tr><th>+ 内容<tr><td>两行结构,colSpan = span
border水平单行内<th>+<td>成对出现tdcolSpan = span * 2 - 1,实现"标签列 + 内容列合并"的对齐
无边框水平单行<td>,内部用 flex 容器包裹标签与内容每个 Item 只占一个单元格

3. 冒号(colon)是如何渲染的

colon属性默认为true。在无边框水平模式下,标签span会带上.has-colon类,由 CSS 伪元素生成冒号(descriptions-item.scss):

.el-descriptions-item__label { &.has-colon { &::after { content: ':'; position: relative; top: -0.5px; } } }

注意:垂直模式与带边框模式下,has-colon会被显式移除(见 descriptions-row.js 与 L98-L99),避免与边框样式中独立的标签单元格视觉冲突。


八、响应式更新与测试佐证

组件对插槽内容的变化是响应式的。单元测试 descriptions.spec.js 中有一个典型场景:通过v-for渲染多个el-descriptions,点击按钮用this.$set修改备注内容后,断言el-tag的文本同步更新为'company'。这说明默认插槽内容会随数据变化自动重渲染,可用于动态详情页。

其余测试还覆盖了:

  • 标题与操作区文本渲染(L10-L25);
  • border是否生成is-bordered类(L27-L40);
  • 组件级label-class-name/content-class-name的传递(L42-L55);
  • column变化时每行子节点数的联动(L57-L75);
  • span是否正确写入colSpan属性(L113-L125)。

九、实战小结

  • 详情展示优先使用默认水平无边框模式,信息密度高且视觉干净;
  • 需要强分隔时加border,此时标签列自动获得浅灰底色与加粗样式;
  • 字段较多、需要换行对齐时,配合columnspan规划栅格,最后一行会自动补全宽度;
  • 需要图标标签或富内容时,使用label插槽与默认插槽;
  • 全项目统一密度时,不必逐个写size,直接配置$ELEMENT.size即可让 Descriptions 自动继承。

相关文件速查:官方文档 examples/docs/zh-CN/descriptions.md · 组件实现 packages/descriptions/src/index.js · 行渲染 packages/descriptions/src/descriptions-row.js · 样式 packages/theme-chalk/src/descriptions.scss · 类型声明 types/descriptions.d.ts。

【免费下载链接】elementA Vue.js 2.0 UI Toolkit for Web项目地址: https://gitcode.com/gh_mirrors/eleme/element

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询