Element UI Descriptions 描述列表组件详解:API 全解与源码渲染机制
【免费下载链接】elementA Vue.js 2.0 UI Toolkit for Web项目地址: https://gitcode.com/gh_mirrors/eleme/element
本文围绕 Element UI(Vue.js 2.0 组件库)的el-descriptions描述列表组件展开,完整覆盖其基础用法、尺寸、垂直布局、自定义样式等全部官方 API,并深入packages/descriptions源码,剖析“占位 Item + 父级集中渲染”的架构设计、getRows换行算法与三种 DOM 结构差异,帮助读者既能快速上手该组件,也能理解其表格布局的底层实现。
Descriptions 用于以列表形式展示多个字段,常见于详情页的信息陈列场景(如用户信息、订单详情)。它本质上是一个语义化的表格:无边框模式下是“标签 + 内容”的松散排列,开启border后则呈现为带分隔线的表格。以下示例与 API 表均继承自仓库中的 es 文档,实现细节以 源码入口 为准。
基础用法
el-descriptions内嵌若干el-descriptions-item,每个 item 通过label属性指定标签文本,默认插槽为内容:
<el-descriptions title="User Info"> <el-descriptions-item label="Username">kooriookami</el-descriptions-item> <el-descriptions-item label="Telephone">18100000000</el-descriptions-item> <el-descriptions-item label="Place">Suzhou</el-descriptions-item> <el-descriptions-item label="Remarks"> <el-tag size="small">School</el-tag> </el-descriptions-item> <el-descriptions-item label="Address">No.1188, Wuzhong Avenue, Wuzhong District, Suzhou, Jiangsu Province</el-descriptions-item> </el-descriptions>其中title显示在列表左上方;内容可以是任意文本或组件(如示例中的el-tag),因为 default 插槽会被原样渲染。
不同尺寸与标签富文本
通过size属性控制列表尺寸,可选medium/small/mini,不传时使用全局尺寸;同时可以结合border、column和extra插槽构建“带操作区”的详情卡片:
<template> <el-radio-group v-model="size"> <el-radio label="">Default</el-radio> <el-radio label="medium">Medium</el-radio> <el-radio label="small">Small</el-radio> <el-radio label="mini">Mini</el-radio> </el-radio-group> <el-descriptions class="margin-top" title="With border" :column="3" :size="size" border> <template slot="extra"> <el-button type="primary" size="small">Operation</el-button> </template> <el-descriptions-item> <template slot="label"> <i class="el-icon-user"></i> Username </template> kooriookami </el-descriptions-item> <el-descriptions-item> <template slot="label"> <i class="el-icon-mobile-phone"></i> Telephone </template> 18100000000 </el-descriptions-item> <el-descriptions-item> <template slot="label"> <i class="el-icon-location-outline"></i> Place </template> Suzhou </el-descriptions-item> <el-descriptions-item> <template slot="label"> <i class="el-icon-tickets"></i> Remarks </template> <el-tag size="small">School</el-tag> </el-descriptions-item> <el-descriptions-item> <template slot="label"> <i class="el-icon-office-building"></i> Address </template> No.1188, Wuzhong Avenue, Wuzhong District, Suzhou, Jiangsu Province </el-descriptions-item> </el-descriptions> <el-descriptions class="margin-top" title="Without border" :column="3" :size="size"> <template slot="extra"> <el-button type="primary" size="small">Operation</el-button> </template> <el-descriptions-item label="Username">kooriookami</el-descriptions-item> <el-descriptions-item label="Telephone">18100000000</el-descriptions-item> <el-descriptions-item label="Place">Suzhou</el-descriptions-item> <el-descriptions-item label="Remarks"> <el-tag size="small">School</el-tag> </el-descriptions-item> <el-descriptions-item label="Address">No.1188, Wuzhong Avenue, Wuzhong District, Suzhou, Jiangsu Province</el-descriptions-item> </el-descriptions> </template> <script> export default { data () { return { size: '' }; } } </script>这里有几个值得注意的 API 组合:
size的解析在 源码 中由计算属性descriptionsSize完成:this.size || (this.$ELEMENT || {}).size,即组件自身未设置时回退到全局配置,最终体现在表格 classel-descriptions--medium等上;el-descriptions-item的label插槽允许标签携带图标等富文本,而不仅仅是label属性;extra插槽用于渲染右上角的操作区,测试用例 test/unit/specs/descriptions.spec.js 验证了title/extra属性会渲染到.el-descriptions__title与.el-descriptions__extra节点。
垂直列表
direction="vertical"让标签位于内容上方(类似表单的上下结构),span控制单个 item 占据的列数:
<el-descriptions title="Vertical list with border" direction="vertical" :column="4" border> <el-descriptions-item label="Username">kooriookami</el-descriptions-item> <el-descriptions-item label="Telephone">18100000000</el-descriptions-item> <el-descriptions-item label="Place" :span="2">Suzhou</el-descriptions-item> <el-descriptions-item label="Remarks"> <el-tag size="small">School</el-tag> </el-descriptions-item> <el-descriptions-item label="Address">No.1188, Wuzhong Avenue, Wuzhong District, Suzhou, Jiangsu Province</el-descriptions-item> </el-descriptions> <el-descriptions class="margin-top" title="Vertical list without border" :column="4" direction="vertical"> <el-descriptions-item label="Username">kooriookami</el-descriptions-item> <el-descriptions-item label="Telephone">18100000000</el-descriptions-item> <el-descriptions-item label="Place" :span="2">Suzhou</el-descriptions-item> <el-descriptions-item label="Remarks"> <el-tag size="small">School</el-tag> </el-descriptions-item> <el-descriptions-item label="Address">No.1188, Wuzhong Avenue, Wuzhong District, Suzhou, Jiangsu Province</el-descriptions-item> </el-descriptions>从源码看,direction只接受horizontal/vertical两个值(prop 定义),在 行渲染组件 中,vertical 模式会为每一组 item 输出两行:第一行是th标签行(colSpan=span),第二行是td内容行;单测 direction props 用例 也验证了两种方向下 DOM 结构确实不同。
自定义样式
label-class-name/content-class-name可分别定制标签与内容的类名,label-style/content-style支持行内样式对象:
<el-descriptions title="Customized style list" :column="3" border> <el-descriptions-item label="Username" label-class-name="my-label" content-class-name="my-content">kooriookami</el-descriptions-item> <el-descriptions-item label="Telephone">18100000000</el-descriptions-item> <el-descriptions-item label="Place">Suzhou</el-descriptions-item> <el-descriptions-item label="Remarks"> <el-tag size="small">School</el-tag> </el-descriptions-item> <el-descriptions-item label="Address" :content-style="{'text-align': 'right'}">No.1188, Wuzhong Avenue, Wuzhong District, Suzhou, Jiangsu Province</el-descriptions-item> </el-descriptions> <style> .my-label { background: #E1F3D8; } .my-content { background: #FDE2E2; } </style>这些类名/样式的生效位置在 descriptions-row.js:item 级别的labelClassName等属性会覆盖父级同名属性(item.props[key] || elDescriptions[key]),这解释了“父级设置兜底、item 级设置优先”的继承关系;对应断言见 class props 测试。
API 参考
el-descriptions Attributes
| Attribute | Description | Type | Accepted Values | Default |
|---|---|---|---|---|
| border | 是否带有边框 | boolean | — | false |
| column | 一行el-descriptions-item的数量 | number | — | 3 |
| direction | 排列的方向 | string | vertical / horizontal | horizontal |
| size | 列表的尺寸 | string | medium / small / mini | — |
| title | 标题文本,显示在左上方 | string | — | — |
| extra | 操作区文本,显示在右上方 | string | — | — |
| colon | 是否显示冒号(覆盖 item 默认值) | boolean | — | true |
| labelClassName | 自定义标签类名 | string | — | — |
| contentClassName | 自定义内容类名 | string | — | — |
| labelStyle | 自定义标签样式 | object | — | — |
| contentStyle | 自定义内容样式 | object | — | — |
以上默认值与 props 定义 完全一致:border: false、column: 3、direction: 'horizontal'、colon: true。
el-descriptions Slots
| Name | Description |
|---|---|
| title | 自定义标题,显示在左上方(优先于title属性) |
| extra | 自定义操作区,显示在右上方(优先于extra属性) |
render 函数 中,仅当title、extra或对应插槽存在时才渲染.el-descriptions__header头部容器,且插槽内容优先于同名属性输出。
el-descriptions-item Attributes
| Attribute | Description | Type | Accepted Values | Default |
|---|---|---|---|---|
| label | 标签文本 | string | — | — |
| span | 占据的列数(列跨度) | number | — | 1 |
| labelClassName | 自定义标签类名 | string | — | — |
| contentClassName | 自定义内容类名 | string | — | — |
| labelStyle | 自定义标签样式 | object | — | — |
| contentStyle | 自定义内容样式 | object | — | — |
el-descriptions-item Slots
| Name | Description |
|---|---|
| label | 自定义标签(可包含图标等富文本) |
| default | 自定义内容(未在上表单列,但为 item 的主插槽) |
源码架构:Item 不渲染 DOM,父级统一排版
理解 Descriptions 的关键在于它的组件分工。el-descriptions-item本身是一个占位组件,其 render 函数直接返回 null:
// packages/descriptions/src/descriptions-item.js export default { name: 'ElDescriptionsItem', props: { label, span, contentClassName, contentStyle, labelClassName, labelStyle }, render() { return null; } };它只负责声明 props 与插槽,真正的 DOM 由el-descriptions在父级统一生成。父组件通过provide/inject把自己暴露为elDescriptions(provide 定义),再由内部的ElDescriptionsRow逐行渲染。这种设计的收益是:换行、补全列宽等跨 item 的排版决策可以在一处集中完成,避免每个 item 自己计算位置。
getRows:换行与补位算法
getRows 方法 是整个布局的核心,逻辑如下:
- 从默认插槽的 vnode 中筛出名为
ElDescriptionsItem的子节点,用getOptionProps/getSlots分别提取合并了默认值的 props(span默认 1)和插槽(label/ default); - 以
column为剩余列数计数器遍历节点:span < count时累计到当前行;span >= count时结束当前行、重置count = column并开始新一行; - 两个特殊修正由 filledNode 完成:
span超过当前行剩余列数时钳制为count;最后一个 item 始终被强制填充整行剩余宽度(isLast分支),保证边框模式下表格末行不会留白。
单测 span props 用例 验证了:span="2"会生成colSpan="2"的单元格;column props 用例 则体现了补位规则在边框/无边框下的不同表象(column=5配 10 个 item,无边框模式首行 5 个单元格,边框模式首行 10 个子节点,因为边框模式每个 item 生成th+td两个单元格)。
三种 DOM 结构
ElDescriptionsRow 的 render 按父级配置输出三种结构:
| 模式 | 结构 | 关键细节 |
|---|---|---|
| vertical | 每行两个<tr>:th标签行 +td内容行 | 单元格colSpan=span;边框模式下标签不再显示冒号(has-colon为 false) |
| horizontal + border | 每个 item 输出th(colSpan=1)+td | td的colSpan = span * 2 - 1,从而让标签列与内容列宽度对称 |
| horizontal 无边框 | 单行<tr>,每格是一个td内含 label/content 两个span | colSpan=span;colon为 true 时 label 追加has-colon类 |
冒号的开关colon只在无边框水平模式下生效(第 99 行 的has-colon: elDescriptions.colon),边框与垂直模式下标签统一不加冒号。
样式侧,descriptions.scss 定义了容器结构:.el-descriptions__table默认table-layout: fixed(列宽均分),而.is-bordered切换为table-layout: auto并为单元格加上边框与12px 10px内边距;尺寸则由el-descriptions--medium/small/mini类级联生效。
安装与引用
组件随 element-ui 完整引入自动注册(src/index.js 第 89-90 行 同时引入 Descriptions 与 DescriptionsItem),也可按需引入:
import { Descriptions, DescriptionsItem } from 'element-ui'; Vue.component(Descriptions.name, Descriptions); Vue.component(DescriptionsItem.name, DescriptionsItem);按需安装的入口文件见 packages/descriptions/index.js 与 packages/descriptions-item/index.js,两者均内置install方法。TypeScript 项目中的属性与插槽签名可参考 types/descriptions.d.ts 和 types/descriptions-item.d.ts。
小结
- Descriptions 以“表格”为骨架展示多字段信息,
column+span决定网格排版,direction与border决定标签与内容的相对位置及外观; - 架构上是典型的“子组件占位、父组件渲染”模式:
ElDescriptionsItem的render返回 null,排版完全由el-descriptions的getRows算法集中决策,末行自动补位保证边框模式下的整齐表格; - 类名与行内样式支持“父级兜底 + item 级覆盖”的两级继承,配合
title/extra/label插槽可以覆盖从纯文本到富文本的操作卡片场景; - 行为均有单测背书,见 test/unit/specs/descriptions.spec.js,可用于回归验证
border、column、direction、span等属性的渲染结果。
【免费下载链接】elementA Vue.js 2.0 UI Toolkit for Web项目地址: https://gitcode.com/gh_mirrors/eleme/element
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考