摘要:本文详细介绍 Element Plus 组件库中的 15 个数据展示组件,包含 Table、Tree、Pagination、Card 等高频使用组件。每个组件提供完整代码示例、核心 API 表格、实战场景及常见问题解答,帮助开发者掌握数据展示最佳实践。
关键词:Vue3、Element Plus、表格组件、树形控件、分页组件、数据展示、前端开发
适合人群:Vue3 中高级开发者、需要实现数据展示功能的开发者、前端工程师
阅读时间:约 30 分钟
版本信息:Element Plus 2.x | Vue 3.x | TypeScript
文章目录
- [1. Table 表格](#1. Table 表格)
-
- [1.1 组件简介](#1.1 组件简介)
- [1.2 基础用法](#1.2 基础用法)
- [1.3 常用场景](#1.3 常用场景)
- 场景一:带排序和筛选的表格
- 场景二:带操作列的表格
- 场景三:带多选和展开行的表格
- [1.4 核心 API](#1.4 核心 API)
- [Table 属性](#Table 属性)
- [Table 事件](#Table 事件)
- [Table-Column 属性](#Table-Column 属性)
- [1.5 注意事项](#1.5 注意事项)
- [2. TableV2 虚拟表格](#2. TableV2 虚拟表格)
-
- [2.1 组件简介](#2.1 组件简介)
- [2.2 基础用法](#2.2 基础用法)
- [2.3 常用场景](#2.3 常用场景)
- 场景一:万级数据渲染
- 场景二:自适应容器尺寸
- [2.4 核心 API](#2.4 核心 API)
- [2.5 注意事项](#2.5 注意事项)
- [3. Tag 标签](#3. Tag 标签)
-
- [3.1 组件简介](#3.1 组件简介)
- [3.2 基础用法](#3.2 基础用法)
- [3.3 常用场景](#3.3 常用场景)
- 场景一:动态标签管理
- [3.4 核心 API](#3.4 核心 API)
- [3.5 注意事项](#3.5 注意事项)
- [4. Progress 进度条](#4. Progress 进度条)
-
- [4.1 组件简介](#4.1 组件简介)
- [4.2 基础用法](#4.2 基础用法)
- [4.3 常用场景](#4.3 常用场景)
- 场景一:环形进度条
- 场景二:自定义颜色渐变
- [4.4 核心 API](#4.4 核心 API)
- [4.5 注意事项](#4.5 注意事项)
- [5. Tree 树形控件](#5. Tree 树形控件)
-
- [5.1 组件简介](#5.1 组件简介)
- [5.2 基础用法](#5.2 基础用法)
- [5.3 常用场景](#5.3 常用场景)
- 场景一:可选中树形控件
- 场景二:懒加载树形控件
- [5.4 核心 API](#5.4 核心 API)
- [5.5 注意事项](#5.5 注意事项)
- [6. TreeV2 虚拟树形控件](#6. TreeV2 虚拟树形控件)
-
- [6.1 组件简介](#6.1 组件简介)
- [6.2 基础用法](#6.2 基础用法)
- [6.3 核心 API](#6.3 核心 API)
- [6.4 注意事项](#6.4 注意事项)
- [7. Pagination 分页](#7. Pagination 分页)
-
- [7.1 组件简介](#7.1 组件简介)
- [7.2 基础用法](#7.2 基础用法)
- [7.3 常用场景](#7.3 常用场景)
- 场景一:小型分页
- 场景二:完整分页配置
- [7.4 核心 API](#7.4 核心 API)
- [7.5 注意事项](#7.5 注意事项)
- [8. Badge 徽标](#8. Badge 徽标)
-
- [8.1 组件简介](#8.1 组件简介)
- [8.2 基础用法](#8.2 基础用法)
- [8.3 核心 API](#8.3 核心 API)
- [8.4 注意事项](#8.4 注意事项)
- [9. Avatar 头像](#9. Avatar 头像)
-
- [9.1 组件简介](#9.1 组件简介)
- [9.2 基础用法](#9.2 基础用法)
- [9.3 常用场景](#9.3 常用场景)
- 场景一:头像组
- [9.4 核心 API](#9.4 核心 API)
- [9.5 注意事项](#9.5 注意事项)
- [10. Skeleton 骨架屏](#10. Skeleton 骨架屏)
-
- [10.1 组件简介](#10.1 组件简介)
- [10.2 基础用法](#10.2 基础用法)
- [10.3 核心 API](#10.3 核心 API)
- [10.4 注意事项](#10.4 注意事项)
- [11. Empty 空状态](#11. Empty 空状态)
-
- [11.1 组件简介](#11.1 组件简介)
- [11.2 基础用法](#11.2 基础用法)
- [11.3 常用场景](#11.3 常用场景)
- 场景一:自定义空状态
- [11.4 核心 API](#11.4 核心 API)
- [11.5 注意事项](#11.5 注意事项)
- [12. Result 结果页](#12. Result 结果页)
-
- [12.1 组件简介](#12.1 组件简介)
- [12.2 基础用法](#12.2 基础用法)
- [12.3 核心 API](#12.3 核心 API)
- [12.4 注意事项](#12.4 注意事项)
- [13. Calendar 日历](#13. Calendar 日历)
-
- [13.1 组件简介](#13.1 组件简介)
- [13.2 基础用法](#13.2 基础用法)
- [13.3 常用场景](#13.3 常用场景)
- 场景一:自定义日历单元格
- [13.4 核心 API](#13.4 核心 API)
- [13.5 注意事项](#13.5 注意事项)
- [14. Card 卡片](#14. Card 卡片)
-
- [14.1 组件简介](#14.1 组件简介)
- [14.2 基础用法](#14.2 基础用法)
- [14.3 常用场景](#14.3 常用场景)
- 场景一:卡片列表
- [14.4 核心 API](#14.4 核心 API)
- [14.5 注意事项](#14.5 注意事项)
- [15. Descriptions 描述列表](#15. Descriptions 描述列表)
-
- [15.1 组件简介](#15.1 组件简介)
- [15.2 基础用法](#15.2 基础用法)
- [15.3 常用场景](#15.3 常用场景)
- 场景一:自定义样式
- [15.4 核心 API](#15.4 核心 API)
- [15.5 注意事项](#15.5 注意事项)
- [💡 综合实战案例](#💡 综合实战案例)
- [❓ 常见问题 FAQ](#❓ 常见问题 FAQ)
-
- [1. Table 数据量大时卡顿怎么办?](#1. Table 数据量大时卡顿怎么办?)
- [2. Tree 节点过多导致性能问题?](#2. Tree 节点过多导致性能问题?)
- [3. Pagination 如何与后端分页配合?](#3. Pagination 如何与后端分页配合?)
- [4. 如何自定义 Empty 组件的图片?](#4. 如何自定义 Empty 组件的图片?)
- [5. Skeleton 如何模拟真实布局?](#5. Skeleton 如何模拟真实布局?)
- [📝 总结](#📝 总结)
- [📚 参考资料](#📚 参考资料)
1. Table 表格
1.1 组件简介
Table 表格组件用于展示结构化数据,支持排序、筛选、分页、固定列等功能。
💡 提示:Table 是后台管理系统中最常用的组件之一,建议优先掌握。
1.2 基础用法
vue
<script setup lang="ts">
import { ref } from 'vue'
interface User {
id: number
name: string
age: number
email: string
}
const tableData = ref<User[]>([
{ id: 1, name: '张三', age: 25, email: 'zhangsan@example.com' },
{ id: 2, name: '李四', age: 30, email: 'lisi@example.com' },
{ id: 3, name: '王五', age: 28, email: 'wangwu@example.com' }
])
</script>
<template>
<el-table :data="tableData" border style="width: 100%">
<el-table-column prop="id" label="ID" width="80" />
<el-table-column prop="name" label="姓名" width="120" />
<el-table-column prop="age" label="年龄" width="80" />
<el-table-column prop="email" label="邮箱" />
</el-table>
</template>
1.3 常用场景
场景一:带排序和筛选的表格
适用于后台管理系统的数据列表,支持按字段排序和条件筛选:
vue
<script setup lang="ts">
import { ref } from 'vue'
const tableData = ref([
{ id: 1, name: '张三', age: 25, city: '北京' },
{ id: 2, name: '李四', age: 30, city: '上海' },
{ id: 3, name: '王五', age: 28, city: '北京' }
])
const handleSort = ({ prop, order }: { prop: string; order: string }) => {
console.log('排序字段:', prop, '排序方式:', order)
}
const handleFilter = (value: string, row: any) => {
return row.city === value
}
</script>
<template>
<el-table :data="tableData" @sort-change="handleSort">
<el-table-column prop="id" label="ID" width="80" sortable />
<el-table-column prop="name" label="姓名" width="120" />
<el-table-column prop="age" label="年龄" width="80" sortable />
<el-table-column
prop="city"
label="城市"
:filters="[
{ text: '北京', value: '北京' },
{ text: '上海', value: '上海' }
]"
:filter-method="handleFilter"
/>
</el-table>
</template>
效果说明:
sortable属性使列支持排序,点击列头可切换升序/降序filters定义筛选选项,filter-method自定义筛选逻辑- 排序变化时会触发
sort-change事件,可在此处请求后端数据
场景二:带操作列的表格
表格最后一列通常放置编辑、删除等操作按钮:
vue
<script setup lang="ts">
import { ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
const tableData = ref([
{ id: 1, name: '张三', age: 25 },
{ id: 2, name: '李四', age: 30 }
])
const handleEdit = (row: any) => {
ElMessage(`编辑: ${row.name}`)
}
const handleDelete = (row: any) => {
ElMessageBox.confirm(`确定删除 ${row.name} 吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
tableData.value = tableData.value.filter(item => item.id !== row.id)
ElMessage('删除成功')
})
}
</script>
<template>
<el-table :data="tableData" border>
<el-table-column prop="id" label="ID" width="80" />
<el-table-column prop="name" label="姓名" width="120" />
<el-table-column prop="age" label="年龄" width="80" />
<el-table-column label="操作" width="180">
<template #default="{ row }">
<el-button size="small" @click="handleEdit(row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</template>
效果说明:
- 使用
#default插槽自定义列内容,{ row }获取当前行数据 - 操作列建议固定宽度,避免按钮换行影响美观
- 删除操作建议二次确认,防止误操作
场景三:带多选和展开行的表格
支持批量操作和查看详细信息:
vue
<script setup lang="ts">
import { ref } from 'vue'
const tableData = ref([
{ id: 1, name: '张三', age: 25, address: '北京市朝阳区' },
{ id: 2, name: '李四', age: 30, address: '上海市浦东新区' }
])
const selectedRows = ref([])
const handleSelectionChange = (selection: any[]) => {
selectedRows.value = selection
console.log('已选中:', selection.length, '条数据')
}
</script>
<template>
<el-table
:data="tableData"
row-key="id"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" />
<el-table-column type="expand">
<template #default="{ row }">
<div style="padding: 20px">
<p>详细地址:{{ row.address }}</p>
</div>
</template>
</el-table-column>
<el-table-column prop="id" label="ID" width="80" />
<el-table-column prop="name" label="姓名" />
<el-table-column prop="age" label="年龄" />
</el-table>
</template>
效果说明:
type="selection"添加多选框列,row-key为必填项type="expand"添加展开行,点击可查看详细信息selection-change事件返回当前选中的所有行数据
1.4 核心 API
Table 属性
| 属性名 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| data | 表格数据 | Array | - | [] |
| border | 是否带有纵向边框 | boolean | - | false |
| stripe | 是否为斑马纹表格 | boolean | - | false |
| height | 表格高度 | string/number | - | - |
| max-height | 表格最大高度 | string/number | - | - |
| show-header | 是否显示表头 | boolean | - | true |
| row-key | 行数据的 Key | string/function | - | - |
| size | 表格尺寸 | string | large / default / small |
default |
| fit | 列的宽度是否自撑开 | boolean | - | true |
| highlight-current-row | 是否高亮当前行 | boolean | - | false |
| current-row-key | 当前行的 key | string/number | - | - |
| empty-text | 空数据时显示的文本 | string | - | 暂无数据 |
Table 事件
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| select | 当用户手动勾选数据行的 Checkbox 时触发 | selection, row |
| select-all | 当用户手动勾选全选 Checkbox 时触发 | selection |
| selection-change | 当选择项发生变化时会触发 | selection |
| row-click | 当某一行被点击时会触发 | row, column, event |
| sort-change | 当表格的排序条件发生变化的时候会触发 | { column, prop, order } |
Table-Column 属性
| 属性名 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| prop | 对应列内容的字段名 | string | - | - |
| label | 显示的标题 | string | - | - |
| width | 列的宽度 | string/number | - | - |
| min-width | 列的最小宽度 | string/number | - | - |
| fixed | 列是否固定 | string/boolean | left / right |
false |
| sortable | 对应列是否可以排序 | boolean | - | false |
| filters | 过滤选项 | Array | - | - |
| filter-method | 过滤方法 | Function | - | - |
| align | 对齐方式 | string | left / center / right |
left |
| show-overflow-tooltip | 超出时是否显示 tooltip | boolean | - | false |
1.5 注意事项
- 大数据量优化 :数据量超过 1000 条时建议使用 TableV2
- row-key 必填 :使用多选或展开行时必须设置
row-key - 固定列宽度:固定列必须设置明确的宽度
- 性能优化:避免在表格中使用过多的自定义渲染
📚 官方文档 :Table 表格 - Element Plus
2. TableV2 虚拟表格
2.1 组件简介
TableV2 是基于虚拟滚动技术的高性能表格组件,适用于大数据量场景。
📖 相关知识:虚拟滚动只渲染可视区域的 DOM 节点,大幅提升性能。
2.2 基础用法
vue
<script setup lang="ts">
import { ref } from 'vue'
import { ElTableV2 } from 'element-plus'
const columns = [
{ key: 'id', title: 'ID', width: 80 },
{ key: 'name', title: '姓名', width: 120 },
{ key: 'age', title: '年龄', width: 80 }
]
const generateData = (count: number) => {
const data = []
for (let i = 0; i < count; i++) {
data.push({
id: i + 1,
name: `用户${i + 1}`,
age: 20 + (i % 30)
})
}
return data
}
const data = ref(generateData(10000))
</script>
<template>
<el-auto-resizer>
<template #default="{ height, width }">
<el-table-v2
:columns="columns"
:data="data"
:width="width"
:height="height"
:row-height="50"
/>
</template>
</el-auto-resizer>
</template>
2.3 常用场景
场景一:万级数据渲染
适用于大数据量场景,如日志列表、订单列表等:
vue
<script setup lang="ts">
import { ref } from 'vue'
import { ElTableV2 } from 'element-plus'
const columns = [
{ key: 'id', title: 'ID', width: 100 },
{ key: 'name', title: '姓名', width: 150 },
{ key: 'email', title: '邮箱', width: 250 },
{ key: 'phone', title: '电话', width: 150 }
]
const data = ref(Array.from({ length: 50000 }, (_, i) => ({
id: i + 1,
name: `用户${i + 1}`,
email: `user${i + 1}@example.com`,
phone: `138${String(i).padStart(8, '0')}`
})))
</script>
<template>
<el-table-v2
:columns="columns"
:data="data"
:width="800"
:height="600"
:row-height="40"
/>
</template>
效果说明:
- 虚拟滚动只渲染可视区域的 DOM 节点,50000 条数据也能流畅滚动
- 必须设置固定的
width、height和row-height - 性能对比:普通 Table 渲染 5000 条数据约 2-3 秒,TableV2 仅需 100-200ms
场景二:自适应容器尺寸
使用 el-auto-resizer 实现响应式布局:
vue
<script setup lang="ts">
import { ref } from 'vue'
import { ElTableV2, ElAutoResizer } from 'element-plus'
const columns = [
{ key: 'id', title: 'ID', width: 80 },
{ key: 'name', title: '姓名', width: 120 },
{ key: 'age', title: '年龄', width: 80 }
]
const generateData = (count: number) => {
const data = []
for (let i = 0; i < count; i++) {
data.push({
id: i + 1,
name: `用户${i + 1}`,
age: 20 + (i % 30)
})
}
return data
}
const data = ref(generateData(10000))
</script>
<template>
<el-auto-resizer>
<template #default="{ height, width }">
<el-table-v2
:columns="columns"
:data="data"
:width="width"
:height="height"
:row-height="50"
/>
</template>
</el-auto-resizer>
</template>
效果说明:
el-auto-resizer自动监听容器尺寸变化- 表格宽度和高度会根据容器自动调整
- 适合全屏表格或响应式布局场景
2.4 核心 API
| 属性名 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| columns | Column\[\] | 列配置 | \[\] |
| data | RowData\[\] | 数据源 | \[\] |
| width | number | 表格宽度 | 必填 |
| height | number | 表格高度 | 必填 |
| row-height | number | 行高 | 50 |
| header-height | number | 表头高度 | 50 |
2.5 注意事项
- 必须设置宽高:TableV2 需要明确的宽度和高度
- 固定行高 :不支持动态行高,需设置固定
row-height - 不支持合并单元格:虚拟表格不支持单元格合并
- 适用场景:数据量 > 1000 条时使用
📚 官方文档 :TableV2 虚拟表格 - Element Plus
3. Tag 标签
3.1 组件简介
Tag 标签用于标记和选择,支持多种类型、尺寸和可关闭状态。
3.2 基础用法
vue
<script setup lang="ts">
import { ref } from 'vue'
const visible = ref(true)
</script>
<template>
<div>
<el-tag>默认标签</el-tag>
<el-tag type="success">成功标签</el-tag>
<el-tag type="info">信息标签</el-tag>
<el-tag type="warning">警告标签</el-tag>
<el-tag type="danger">危险标签</el-tag>
<el-tag v-if="visible" closable @close="visible = false">可关闭标签</el-tag>
</div>
</template>
3.3 常用场景
场景一:动态标签管理
用户可以添加、删除标签,常用于文章标签、技能标签等场景:
vue
<script setup lang="ts">
import { ref } from 'vue'
const tags = ref(['Vue', 'React', 'Angular'])
const inputVisible = ref(false)
const inputValue = ref('')
const handleClose = (tag: string) => {
tags.value.splice(tags.value.indexOf(tag), 1)
}
const showInput = () => {
inputVisible.value = true
}
const handleInputConfirm = () => {
if (inputValue.value && !tags.value.includes(inputValue.value)) {
tags.value.push(inputValue.value)
}
inputVisible.value = false
inputValue.value = ''
}
</script>
<template>
<div>
<el-tag
v-for="tag in tags"
:key="tag"
closable
@close="handleClose(tag)"
style="margin: 0 8px 8px 0"
>
{{ tag }}
</el-tag>
<el-input
v-if="inputVisible"
v-model="inputValue"
size="small"
style="width: 100px"
@keyup.enter="handleInputConfirm"
@blur="handleInputConfirm"
/>
<el-button v-else size="small" @click="showInput">+ 添加标签</el-button>
</div>
</template>
效果说明:
closable属性使标签可关闭,点击关闭图标触发close事件- 使用
v-if控制输入框的显示/隐藏,点击按钮或失焦时确认添加 @keyup.enter支持回车键快速添加,提升用户体验
3.4 核心 API
| 属性名 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| type | 标签类型 | string | success / info / warning / danger |
'' |
| closable | 是否可关闭 | boolean | - | false |
| size | 标签尺寸 | string | large / default / small |
default |
| effect | 主题效果 | string | light / dark / plain |
light |
| color | 背景色 | string | - | - |
| hit | 是否有边框描边 | boolean | - | false |
| round | 是否为圆角 | boolean | - | false |
3.5 注意事项
- 自定义颜色 :使用
color属性可设置任意背景色 - effect 属性 :支持
light、dark、plain三种效果 - 关闭事件 :关闭时触发
close事件
📚 官方文档 :Tag 标签 - Element Plus
4. Progress 进度条
4.1 组件简介
Progress 进度条用于展示操作进度,支持线性和环形两种样式。
4.2 基础用法
vue
<script setup lang="ts">
import { ref } from 'vue'
const percentage = ref(50)
</script>
<template>
<div>
<el-progress :percentage="percentage" />
<el-progress :percentage="100" status="success" />
<el-progress :percentage="80" status="warning" />
<el-progress :percentage="60" status="exception" />
<el-progress :percentage="70" :stroke-width="20" />
</div>
</template>
4.3 常用场景
场景一:环形进度条
适用于展示完成度、占比等场景:
vue
<template>
<div>
<el-progress type="circle" :percentage="75" />
<el-progress type="circle" :percentage="100" status="success" />
<el-progress type="circle" :percentage="80" :stroke-width="15" />
</div>
</template>
效果说明:
type="circle"切换为环形模式status可设置success(成功)、exception(异常)、warning(警告)stroke-width控制环形宽度,数值越大环越粗
场景二:自定义颜色渐变
根据进度值动态改变颜色,增强视觉反馈:
vue
<template>
<el-progress
:percentage="85"
:color="customColors"
/>
</template>
<script setup lang="ts">
const customColors = [
{ color: '#f56c6c', percentage: 20 },
{ color: '#e6a23c', percentage: 40 },
{ color: '#5cb87a', percentage: 60 },
{ color: '#1989fa', percentage: 80 },
{ color: '#6f7ad3', percentage: 100 }
]
</script>
效果说明:
color支持数组,根据percentage值自动切换对应区间的颜色- 0-20% 显示红色(警告),40-60% 显示绿色(正常),80-100% 显示蓝色(优秀)
- 适合文件上传、任务进度等需要视觉区分状态的场景
4.4 核心 API
| 属性名 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| percentage | 百分比(必填) | number | 0-100 | 0 |
| type | 进度条类型 | string | line / circle / dashboard |
line |
| stroke-width | 进度条宽度 | number | - | 6 |
| status | 当前状态 | string | success / exception / warning |
- |
| color | 进度条颜色 | string/function/array | - | - |
| show-text | 是否显示文字 | boolean | - | true |
| text-inside | 文字是否显示在进度条内 | boolean | - | false |
| width | 环形进度条宽度 | number | - | 126 |
4.5 注意事项
- percentage 必填:必须设置 0-100 的数值
- status 优先级:设置 status 后会覆盖 color 属性
- 环形尺寸 :使用
width属性设置环形进度条尺寸
📚 官方文档 :Progress 进度条 - Element Plus
5. Tree 树形控件
5.1 组件简介
Tree 树形控件用于展示具有层级关系的数据,支持展开/折叠、选中、拖拽等操作。
5.2 基础用法
vue
<script setup lang="ts">
import { ref } from 'vue'
const treeData = ref([
{
label: '一级 1',
children: [
{
label: '二级 1-1',
children: [{ label: '三级 1-1-1' }]
}
]
},
{
label: '一级 2',
children: [
{ label: '二级 2-1' },
{ label: '二级 2-2' }
]
}
])
</script>
<template>
<el-tree :data="treeData" :props="{ children: 'children', label: 'label' }" />
</template>
5.3 常用场景
场景一:可选中树形控件
适用于权限管理、分类选择等需要多选的场景:
vue
<script setup lang="ts">
import { ref } from 'vue'
const treeRef = ref()
const treeData = ref([
{ id: 1, label: '北京', children: [{ id: 4, label: '朝阳区' }] },
{ id: 2, label: '上海', children: [{ id: 5, label: '浦东新区' }] },
{ id: 3, label: '广州' }
])
const getCheckedNodes = () => {
console.log(treeRef.value.getCheckedNodes())
}
</script>
<template>
<div>
<el-tree
ref="treeRef"
:data="treeData"
show-checkbox
node-key="id"
:props="{ children: 'children', label: 'label' }"
/>
<el-button @click="getCheckedNodes">获取选中节点</el-button>
</div>
</template>
效果说明:
show-checkbox显示复选框,支持多选node-key为必填项,用于唯一标识每个节点- 通过
ref调用getCheckedNodes()获取选中节点
场景二:懒加载树形控件
适用于数据量大或需要异步加载的场景:
vue
<script setup lang="ts">
const loadNode = (node: any, resolve: Function) => {
if (node.level === 0) {
return resolve([{ label: '根节点' }])
}
if (node.level >= 1) {
return resolve([
{ label: `子节点 ${node.level}` },
{ label: `子节点 ${node.level + 1}` }
])
}
}
</script>
<template>
<el-tree :props="{ label: 'label' }" :load="loadNode" lazy />
</template>
效果说明:
lazy开启懒加载模式,节点展开时才会加载子节点load方法接收node和resolve两个参数- 适合树形数据量大、需要按需加载的场景(如文件系统、组织架构)
5.4 核心 API
| 属性名 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| data | 树形数据 | Array | - | [] |
| props | 配置选项 | object | - | { children: 'children', label: 'label' } |
| show-checkbox | 节点是否可被选择 | boolean | - | false |
| node-key | 每个树节点用来作为唯一标识的属性 | string | - | - |
| lazy | 是否懒加载 | boolean | - | false |
| load | 加载子树数据的方法 | Function | - | - |
| accordion | 是否每次只打开一个同级树节点 | boolean | - | false |
| default-expand-all | 是否默认展开所有节点 | boolean | - | false |
| highlight-current | 是否高亮当前选中节点 | boolean | - | false |
5.5 注意事项
- node-key 必填 :使用选中功能时必须设置
node-key - 懒加载 :需要配合
load方法使用 - 大数据优化 :节点超过 1000 个时建议使用 TreeV2
📚 官方文档 :Tree 树形控件 - Element Plus
6. TreeV2 虚拟树形控件
6.1 组件简介
TreeV2 是基于虚拟滚动的树形控件,适用于大数据量场景。
6.2 基础用法
vue
<script setup lang="ts">
import { ref } from 'vue'
const treeData = ref(
Array.from({ length: 1000 }, (_, i) => ({
id: `${i}`,
label: `节点 ${i}`,
children: []
}))
)
</script>
<template>
<el-tree-v2
:data="treeData"
:props="{ children: 'children', label: 'label' }"
:height="400"
/>
</template>
6.3 核心 API
| 属性名 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| data | Array | 树形数据 | \[\] |
| props | object | 配置选项 | { children: 'children', label: 'label' } |
| height | number | 树控件高度 | 必填 |
6.4 注意事项
- 必须设置高度:TreeV2 需要明确的高度才能正常工作
- 不支持拖拽:虚拟树形控件暂不支持节点拖拽
- 适用场景:节点数量 > 1000 时使用
📚 官方文档 :TreeV2 虚拟树形控件 - Element Plus
7. Pagination 分页
7.1 组件简介
Pagination 分页组件用于数据分页展示,支持多种布局和自定义配置。
7.2 基础用法
vue
<script setup lang="ts">
import { ref } from 'vue'
const currentPage = ref(1)
const pageSize = ref(10)
const total = ref(100)
</script>
<template>
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</template>
<script setup lang="ts">
const handleSizeChange = (val: number) => {
console.log(`每页 ${val} 条`)
}
const handleCurrentChange = (val: number) => {
console.log(`当前页: ${val}`)
}
</script>
7.3 常用场景
场景一:小型分页
适用于数据量较少、不需要复杂分页的场景:
vue
<template>
<el-pagination
:total="50"
layout="prev, pager, next"
:pager-count="5"
/>
</template>
效果说明:
layout="prev, pager, next"只显示上一页、页码、下一页pager-count控制显示的页码按钮数量,必须为奇数- 适合总页数少于10页的简单场景
场景二:完整分页配置
包含总数、每页条数选择器、跳转等完整功能:
vue
<script setup lang="ts">
import { ref } from 'vue'
const currentPage = ref(1)
const pageSize = ref(10)
const total = ref(100)
const handleSizeChange = (val: number) => {
console.log(`每页 ${val} 条`)
// 重新请求数据
}
const handleCurrentChange = (val: number) => {
console.log(`当前页: ${val}`)
// 重新请求数据
}
</script>
<template>
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</template>
效果说明:
v-model:current-page和v-model:page-size支持双向绑定layout可自由组合:total(总数)、sizes(每页条数)、prev/next(上下页)、pager(页码)、jumper(跳转)- 分页变化时需要重新请求后端数据
7.4 核心 API
| 属性名 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| total | 总条目数(必填) | number | - | - |
| page-size | 每页显示条目数 | number | - | 10 |
| current-page | 当前页数 | number | - | 1 |
| page-sizes | 每页显示个数选择器的选项 | Array | - | [10, 20, 30, 40, 50, 100] |
| layout | 组件布局 | string | total / sizes / prev / pager / next / jumper |
prev, pager, next, jumper |
| pager-count | 页码按钮的数量 | number | 5-21的奇数 | 7 |
| background | 是否为分页按钮添加背景色 | boolean | - | false |
| disabled | 是否禁用 | boolean | - | false |
7.5 注意事项
- total 必填:必须设置总条目数
- layout 组合 :可自由组合
total, sizes, prev, pager, next, jumper - 与表格配合:分页变化时重新请求数据
📚 官方文档 :Pagination 分页 - Element Plus
8. Badge 徽标
8.1 组件简介
Badge 徽标组件用于显示新消息数量或状态提示。
8.2 基础用法
vue
<script setup lang="ts">
import { ref } from 'vue'
const messageCount = ref(5)
</script>
<template>
<el-badge :value="messageCount">
<el-button>消息</el-button>
</el-badge>
<el-badge :value="0" :max="99">
<el-button>通知</el-button>
</el-badge>
<el-badge is-dot>
<el-button>红点</el-button>
</el-badge>
</template>
8.3 核心 API
| 属性名 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| value | 显示值 | string/number | - | '' |
| max | 最大值 | number | - | 99 |
| is-dot | 小圆点 | boolean | - | false |
| hidden | 隐藏 badge | boolean | - | false |
| type | 类型 | string | primary / success / warning / danger / info |
danger |
8.4 注意事项
- is-dot 模式:只显示红点,不显示数值
- hidden 属性:可动态控制徽标显示/隐藏
- 自定义内容:可使用默认插槽自定义内容
📚 官方文档 :Badge 徽标 - Element Plus
9. Avatar 头像
9.1 组件简介
Avatar 头像组件用于展示用户头像,支持图片、图标、文字三种形式。
9.2 基础用法
vue
<template>
<el-avatar src="https://example.com/avatar.jpg" />
<el-avatar>U</el-avatar>
<el-avatar :size="50">User</el-avatar>
<el-avatar shape="square">S</el-avatar>
</template>
9.3 常用场景
场景一:头像组
适用于团队成员展示、群成员列表等场景:
vue
<template>
<el-avatar-group :max="3">
<el-avatar src="https://example.com/1.jpg" />
<el-avatar src="https://example.com/2.jpg" />
<el-avatar src="https://example.com/3.jpg" />
<el-avatar src="https://example.com/4.jpg" />
</el-avatar-group>
</template>
效果说明:
el-avatar-group将多个头像组合展示:max="3"表示最多显示3个头像,超出的会显示为+1等形式- 头像会部分重叠,形成视觉上的群组效果
9.4 核心 API
| 属性名 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| src | 图片地址 | string | - | - |
| size | 头像尺寸 | number/string | - | 40 |
| shape | 形状 | string | circle / square |
circle |
| icon | 图标类型 | Component | - | - |
| fit | 图片填充模式 | string | fill / contain / cover / none / scale-down |
cover |
| alt | 图片 alt 属性 | string | - | - |
9.5 注意事项
- 图片加载失败:会自动显示 fallback 内容
- 头像组 :使用
el-avatar-group组件 - 自定义尺寸:支持数值和 CSS 单位
📚 官方文档 :Avatar 头像 - Element Plus
10. Skeleton 骨架屏
10.1 组件简介
Skeleton 骨架屏用于在数据加载时显示占位内容,提升用户体验。
10.2 基础用法
vue
<script setup lang="ts">
import { ref } from 'vue'
const loading = ref(true)
setTimeout(() => {
loading.value = false
}, 2000)
</script>
<template>
<el-skeleton :loading="loading" :rows="5" animated>
<template #template>
<el-skeleton-item variant="image" style="width: 100px; height: 100px" />
<el-skeleton-item variant="text" style="width: 200px" />
<el-skeleton-item variant="text" style="width: 150px" />
</template>
<template #default>
<div>实际内容</div>
</template>
</el-skeleton>
</template>
10.3 核心 API
| 属性名 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| loading | boolean | 是否显示骨架屏 | true |
| rows | number | 占位行数 | 3 |
| animated | boolean | 是否显示动画 | false |
| throttle | number | 渲染延迟(ms) | 0 |
10.4 注意事项
- loading 控制 :通过
loading属性切换显示状态 - 自定义形状 :使用
variant属性设置占位形状 - 动画效果 :设置
animated提升加载体验
📚 官方文档 :Skeleton 骨架屏 - Element Plus
11. Empty 空状态
11.1 组件简介
Empty 空状态组件用于展示数据为空时的提示。
11.2 基础用法
vue
<template>
<el-empty description="暂无数据" />
<el-empty :image-size="200" />
</template>
11.3 常用场景
场景一:自定义空状态
带有操作按钮的空状态,引导用户进行下一步操作:
vue
<template>
<el-empty description="暂无订单">
<el-button type="primary" @click="goShopping">去逛逛</el-button>
</el-empty>
</template>
<script setup lang="ts">
const goShopping = () => {
console.log('跳转到购物页面')
}
</script>
效果说明:
- 使用默认插槽可以在空状态下方添加操作按钮
- 引导用户进行操作,避免空白页面带来的困惑
- 适合订单列表、消息列表等需要引导用户的场景
11.4 核心 API
| 属性名 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| image | 图片地址 | string | - | - |
| image-size | 图片尺寸 | number | - | 160 |
| description | 描述文字 | string | - | 暂无数据 |
11.5 注意事项
- 自定义图片:可传入自定义图片 URL
- 默认插槽:可添加按钮或其他操作
- 配合表格:数据为空时显示 Empty 组件
📚 官方文档 :Empty 空状态 - Element Plus
12. Result 结果页
12.1 组件简介
Result 结果页用于展示操作结果,如成功、失败、警告等状态。
12.2 基础用法
vue
<template>
<el-result
icon="success"
title="操作成功"
sub-title="您的订单已提交成功"
>
<template #extra>
<el-button type="primary">返回首页</el-button>
</template>
</el-result>
</template>
12.3 核心 API
| 属性名 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| icon | 图标类型 | string | success / warning / info / error |
info |
| title | 标题 | string | - | '' |
| sub-title | 副标题 | string | - | '' |
12.4 注意事项
- icon 类型 :支持
success、warning、info、error - extra 插槽:用于放置操作按钮
- 配合路由:常用于操作结果页面
📚 官方文档 :Result 结果页 - Element Plus
13. Calendar 日历
13.1 组件简介
Calendar 日历组件用于展示日期信息,支持自定义单元格内容。
13.2 基础用法
vue
<script setup lang="ts">
import { ref } from 'vue'
const selectedDate = ref(new Date())
</script>
<template>
<el-calendar v-model="selectedDate" />
</template>
13.3 常用场景
场景一:自定义日历单元格
在日历中标记特殊日期,如节日、活动等:
vue
<template>
<el-calendar>
<template #date-cell="{ data }">
<div>
{{ data.day.split('-').slice(1).join('-') }}
<div v-if="data.day === '2024-01-01'" class="event">元旦</div>
</div>
</template>
</el-calendar>
</template>
效果说明:
- 使用
#date-cell插槽自定义每个日期单元格的显示内容 data.day返回格式为YYYY-MM-DD的日期字符串- 可以根据业务需求在特定日期上添加标记、事件等
13.4 核心 API
| 属性名 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| v-model | 绑定值 | Date | - | - |
| range | 时间范围 | string | - | - |
13.5 注意事项
- 自定义单元格 :使用
date-cell插槽 - 范围限制 :使用
range属性限制可选日期 - 配合表单:可作为日期选择器的替代方案
📚 官方文档 :Calendar 日历 - Element Plus
14. Card 卡片
14.1 组件简介
Card 卡片组件用于展示内容区块,支持自定义头部和阴影效果。
14.2 基础用法
vue
<template>
<el-card header="卡片标题">
<p>卡片内容</p>
</el-card>
<el-card shadow="always">
<p>始终显示阴影</p>
</el-card>
</template>
14.3 常用场景
场景一:卡片列表
使用栅格布局展示响应式卡片网格:
vue
<script setup lang="ts">
import { ref } from 'vue'
const cards = ref([
{ title: '卡片1', content: '内容1' },
{ title: '卡片2', content: '内容2' },
{ title: '卡片3', content: '内容3' }
])
</script>
<template>
<el-row :gutter="20">
<el-col v-for="card in cards" :key="card.title" :span="8">
<el-card :header="card.title">
<p>{{ card.content }}</p>
</el-card>
</el-col>
</el-row>
</template>
效果说明:
el-row和el-col实现栅格布局,:span="8"表示每行显示3个卡片:gutter="20"设置卡片之间的间距为20px- 适合产品展示、文章列表、用户列表等场景
14.4 核心 API
| 属性名 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| header | 卡片标题 | string | - | - |
| shadow | 阴影显示时机 | string | always / hover / never |
always |
| body-style | 卡片 body 样式 | object | - | {} |
14.5 注意事项
- header 插槽 :可使用
#header插槽自定义头部 - 阴影控制 :
shadow支持always、hover、never - 响应式布局 :配合 Layout 组件使用
📚 官方文档 :Card 卡片 - Element Plus
15. Descriptions 描述列表
15.1 组件简介
Descriptions 描述列表用于展示多个字段的键值对信息。
15.2 基础用法
vue
<template>
<el-descriptions title="用户信息" :column="2" border>
<el-descriptions-item label="用户名">张三</el-descriptions-item>
<el-descriptions-item label="手机号">13800138000</el-descriptions-item>
<el-descriptions-item label="邮箱">zhangsan@example.com</el-descriptions-item>
<el-descriptions-item label="地址">北京市朝阳区</el-descriptions-item>
</el-descriptions>
</template>
15.3 常用场景
场景一:自定义样式
使用跨列、标签、徽标等元素丰富描述列表的展示效果:
vue
<template>
<el-descriptions :column="3" border>
<el-descriptions-item label="产品" :span="2">
<el-tag size="small">Element Plus</el-tag>
</el-descriptions-item>
<el-descriptions-item label="版本">2.x</el-descriptions-item>
<el-descriptions-item label="状态">
<el-badge value="new" />
</el-descriptions-item>
</el-descriptions>
</template>
效果说明:
:span="2"让"产品"单元格跨2列,突出重要信息- 可以在单元格内嵌套 Tag、Badge 等组件
border模式带边框,更适合展示详细信息
15.4 核心 API
| 属性名 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| title | 标题 | string | - | - |
| column | 列数 | number | - | 3 |
| border | 是否带有边框 | boolean | - | false |
| size | 尺寸 | string | large / default / small |
default |
| direction | 排列方向 | string | horizontal / vertical |
horizontal |
15.5 注意事项
- span 属性:可设置单元格跨列
- border 模式:带边框更适合展示详细信息
- 配合卡片 :常与 Card 组件配合使用
📚 官方文档 :Descriptions 描述列表 - Element Plus
💡 综合实战案例
用户管理页面
结合 Table、Pagination、Tag、Badge、Avatar、Card、Descriptions 等组件实现完整的用户管理页面。
vue
<script setup lang="ts">
import { ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
interface User {
id: number
name: string
email: string
role: string
status: 'active' | 'inactive'
avatar: string
}
const loading = ref(false)
const tableData = ref<User[]>([])
const currentPage = ref(1)
const pageSize = ref(10)
const total = ref(0)
const selectedUser = ref<User | null>(null)
const dialogVisible = ref(false)
const fetchUsers = async () => {
loading.value = true
// 模拟 API 请求
setTimeout(() => {
tableData.value = Array.from({ length: pageSize.value }, (_, i) => ({
id: (currentPage.value - 1) * pageSize.value + i + 1,
name: `用户${i + 1}`,
email: `user${i + 1}@example.com`,
role: i % 2 === 0 ? '管理员' : '普通用户',
status: i % 3 === 0 ? 'inactive' : 'active',
avatar: `https://example.com/avatar${i % 5}.jpg`
}))
total.value = 100
loading.value = false
}, 500)
}
const handleDelete = (row: User) => {
ElMessageBox.confirm(`确定删除 ${row.name} 吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
ElMessage('删除成功')
fetchUsers()
})
}
const handlePageChange = (page: number) => {
currentPage.value = page
fetchUsers()
}
const handleSizeChange = (size: number) => {
pageSize.value = size
currentPage.value = 1
fetchUsers()
}
const viewDetail = (row: User) => {
selectedUser.value = row
dialogVisible.value = true
}
fetchUsers()
</script>
<template>
<el-card header="用户管理">
<el-table :data="tableData" v-loading="loading" border>
<el-table-column label="头像" width="80">
<template #default="{ row }">
<el-avatar :size="40" :src="row.avatar">{{ row.name[0] }}</el-avatar>
</template>
</el-table-column>
<el-table-column prop="id" label="ID" width="80" />
<el-table-column prop="name" label="姓名" width="120" />
<el-table-column prop="email" label="邮箱" />
<el-table-column label="角色" width="120">
<template #default="{ row }">
<el-tag :type="row.role === '管理员' ? 'danger' : 'primary'">
{{ row.role }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="状态" width="100">
<template #default="{ row }">
<el-badge :is-dot="row.status === 'active'" :hidden="row.status === 'inactive'">
<el-tag :type="row.status === 'active' ? 'success' : 'info'">
{{ row.status === 'active' ? '活跃' : '禁用' }}
</el-tag>
</el-badge>
</template>
</el-table-column>
<el-table-column label="操作" width="200">
<template #default="{ row }">
<el-button size="small" @click="viewDetail(row)">详情</el-button>
<el-button size="small" type="danger" @click="handleDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:total="total"
:page-sizes="[10, 20, 50]"
layout="total, sizes, prev, pager, next"
@current-change="handlePageChange"
@size-change="handleSizeChange"
style="margin-top: 20px; justify-content: flex-end"
/>
</el-card>
<el-dialog v-model="dialogVisible" title="用户详情" width="600px">
<el-descriptions v-if="selectedUser" :column="2" border>
<el-descriptions-item label="ID">{{ selectedUser.id }}</el-descriptions-item>
<el-descriptions-item label="姓名">{{ selectedUser.name }}</el-descriptions-item>
<el-descriptions-item label="邮箱">{{ selectedUser.email }}</el-descriptions-item>
<el-descriptions-item label="角色">{{ selectedUser.role }}</el-descriptions-item>
</el-descriptions>
</el-dialog>
</template>
❓ 常见问题 FAQ
1. Table 数据量大时卡顿怎么办?
解决方案:
- 使用 TableV2 虚拟滚动
- 开启
lazy懒加载 - 减少自定义列渲染
- 使用
row-key优化渲染
vue
<!-- 使用 TableV2 -->
<el-table-v2
:columns="columns"
:data="largeData"
:width="800"
:height="600"
/>
📖 扩展阅读 :TableV2 官方文档
2. Tree 节点过多导致性能问题?
解决方案:
- 使用 TreeV2
- 开启懒加载
- 按需展开节点
vue
<el-tree-v2 :data="largeTreeData" :height="500" />
3. Pagination 如何与后端分页配合?
解决方案:监听分页变化事件,重新请求数据。
vue
<script setup lang="ts">
const handleCurrentChange = (page: number) => {
fetchList({ page, pageSize: pageSize.value })
}
</script>
4. 如何自定义 Empty 组件的图片?
解决方案 :使用 image 属性传入自定义图片 URL。
vue
<el-empty image="https://example.com/custom-empty.png" description="自定义空状态" />
5. Skeleton 如何模拟真实布局?
解决方案 :使用 variant 属性设置不同占位形状。
vue
<el-skeleton-item variant="image" style="width: 100px; height: 100px" />
<el-skeleton-item variant="text" />
<el-skeleton-item variant="button" />
📝 总结
本文介绍了 Element Plus 的 15 个数据展示组件,涵盖表格、树形、分页、标签、进度条等常用场景。
组件使用频率
| 组件 | 使用频率 | 推荐指数 |
|---|---|---|
| Table | ⭐⭐⭐⭐⭐ | 必学 |
| Pagination | ⭐⭐⭐⭐⭐ | 必学 |
| Tag | ⭐⭐⭐⭐ | 高频 |
| Card | ⭐⭐⭐⭐ | 高频 |
| Tree | ⭐⭐⭐⭐ | 高频 |
| Badge | ⭐⭐⭐ | 常用 |
| Avatar | ⭐⭐⭐ | 常用 |
| Progress | ⭐⭐⭐ | 常用 |
| Skeleton | ⭐⭐⭐ | 常用 |
| Empty | ⭐⭐⭐ | 常用 |
| Descriptions | ⭐⭐ | 一般 |
| Result | ⭐⭐ | 一般 |
| Calendar | ⭐⭐ | 一般 |
| TableV2 | ⭐ | 特定场景 |
| TreeV2 | ⭐ | 特定场景 |
学习建议
- 优先掌握 Table、Pagination、Tree 三个核心组件
- 大数据量场景使用 TableV2 和 TreeV2
- 配合 Form 组件 实现完整的数据管理功能
- 建议配合官方文档学习,获取最新 API 信息
📚 参考资料
官方文档
- Element Plus 官方文档
- Table 表格 - Element Plus
- TableV2 虚拟表格 - Element Plus
- Tag 标签 - Element Plus
- Progress 进度条 - Element Plus
- Tree 树形控件 - Element Plus
- TreeV2 虚拟树形控件 - Element Plus
- Pagination 分页 - Element Plus
- Badge 徽标 - Element Plus
- Avatar 头像 - Element Plus
- Skeleton 骨架屏 - Element Plus
- Empty 空状态 - Element Plus
- Result 结果页 - Element Plus
- Calendar 日历 - Element Plus
- Card 卡片 - Element Plus
- Descriptions 描述列表 - Element Plus
相关技术文档
📌 下一篇预告 :导航与反馈组件 - 包含 Breadcrumb、Menu、Dialog、Drawer 等 15 个导航与反馈相关组件的详细使用指南。