el-pagination el-table
这两个组件是后台管理系统中最常用的数据展示与交互组合,通常配合使用实现 分页加载、排序、筛选、操作 等功能。
一、分页组件 el-pagination
用于控制大量数据的分页展示。
✅ 基本结构
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:total="total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
background
/>
🔧 核心属性(Props)
属性 | 类型 | 说明 | 默认值 |
---|---|---|---|
v-model:current-page |
number | 当前页码(双向绑定) | 1 |
v-model:page-size |
number | 每页条数(双向绑定) | 10 |
total |
number | 总数据条数 | 0 |
page-sizes |
number[] | 每页显示条数选择器选项 | [10, 20, 30, 40, 50, 100] |
layout |
string | 组件布局,用逗号分隔 | 'prev, pager, next' |
background |
boolean | 是否为按钮添加背景色 | false |
disabled |
boolean | 是否禁用分页 | false |
small |
boolean | 是否使用小型分页 | false |
layout
可选值:
total
: 总条数sizes
: 每页条数选择器prev
: 上一页pager
: 页码列表next
: 下一页jumper
: 跳转输入框->
: 分隔符(将后续元素推到右侧)
📢 事件(Events)
事件 | 说明 | 回调参数 |
---|---|---|
@size-change |
每页条数改变时触发 | 改变后的 pageSize |
@current-change |
当前页改变时触发 | 改变后的 currentPage |
@prev-click |
点击上一页时触发 | - |
@next-click |
点击下一页时触发 | - |
⚠️ 注意:使用
v-model
后,通常只需监听@size-change
和@current-change
来重新请求数据。
二、表格组件 el-table
用于展示结构化数据。
✅ 基本结构
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="name" label="姓名" />
<el-table-column prop="age" label="年龄" />
</el-table>
🔧 表格核心属性(el-table
Props)
属性 | 类型 | 说明 |
---|---|---|
data |
array | 显示的数据源 |
stripe |
boolean | 是否显示斑马纹 |
border |
boolean | 是否显示纵向边框 |
fit |
boolean | 列宽是否自撑开 |
height |
string/number | 固定高度,超出出现滚动条 |
max-height |
string/number | 最大高度 |
highlight-current-row |
boolean | 高亮当前行 |
empty-text |
string | 数据为空时显示文本 |
v-loading |
boolean | 是否显示加载中 |
🔧 列定义 el-table-column
属性
属性 | 类型 | 说明 |
---|---|---|
type |
string | 列类型:selection , index , expand |
label |
string | 列标题 |
prop |
string | 对应字段名 |
width / min-width |
string/number | 列宽 |
fixed |
string/boolean | 固定列:left , right |
sortable |
boolean/string | 是否可排序,custom 为自定义 |
formatter |
Function | 格式化内容函数 |
show-overflow-tooltip |
boolean | 内容过长显示 tooltip |
align / header-align |
string | 对齐方式:left , center , right |
🧩 高级功能
1. 复选框列
<el-table-column type="selection" width="55" />
2. 序号列
<el-table-column type="index" label="序号" width="80" />
3. 可展开行
<el-table-column type="expand">
<template #default="props">
<p>详情:{{ props.row.detail }}</p>
</template>
</el-table-column>
4. 自定义列模板
<el-table-column label="操作" width="180">
<template #default="{ row }">
<el-button size="small" @click="edit(row)">编辑</el-button>
<el-button size="small" type="danger">删除</el-button>
</template>
</el-table-column>
5. 排序
<el-table-column prop="age" label="年龄" sortable />
<!-- 或自定义排序 -->
<el-table-column prop="age" label="年龄" sortable="custom" @sort-change="handleSort" />
6. 筛选
<el-table-column
prop="tag"
label="标签"
:filters="[{ text: '家', value: '家' }, { text: '公司', value: '公司' }]"
:filter-method="filterTag"
/>
function filterTag(value, row) {
return row.tag === value
}
三、实战案例(完整)
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
// 响应式数据
const tableData = ref([])
const total = ref(0)
const loading = ref(false)
// 分页
const currentPage = ref(1)
const pageSize = ref(10)
// 搜索与排序
const searchKey = ref('')
const sortState = reactive({ prop: '', order: '' })
// 模拟数据获取
const fetchData = () => {
loading.value = true
setTimeout(() => {
const allData = Array.from({ length: 100 }, (_, i) => ({
id: i + 1,
name: `用户${i + 1}`,
age: 18 + (i % 50),
address: `地址 ${i + 1}`
}))
// 搜索
let filtered = allData.filter(item => item.name.includes(searchKey.value))
// 排序
if (sortState.prop && sortState.order) {
filtered.sort((a, b) => {
const diff = a[sortState.prop] - b[sortState.prop]
return sortState.order === 'descending' ? -diff : diff
})
}
// 分页
const start = (currentPage.value - 1) * pageSize.value
const end = start + pageSize.value
tableData.value = filtered.slice(start, end)
total.value = filtered.length
loading.value = false
}, 500)
}
// 事件
const handleSearch = () => {
currentPage.value = 1
fetchData()
}
const handleSortChange = ({ prop, order }) => {
sortState.prop = prop
sortState.order = order
currentPage.value = 1
fetchData()
}
const handleEdit = (row) => ElMessage.info(`编辑:${row.name}`)
const handleDelete = (row) => {
ElMessageBox.confirm(`删除 ${row.name}?`, '确认', { type: 'warning' })
.then(() => ElMessage.success('删除成功'))
.catch(() => ElMessage.info('取消'))
}
onMounted(() => fetchData())
</script>
<template>
<div class="p-4">
<div class="flex justify-between mb-4">
<h3 class="text-lg font-medium">用户列表</h3>
<el-input v-model="searchKey" placeholder="搜索姓名" @input="handleSearch" style="width: 240px" />
</div>
<el-table :data="tableData" stripe border v-loading="loading" @sort-change="handleSortChange">
<el-table-column type="index" label="序号" width="80" />
<el-table-column prop="name" label="姓名" sortable />
<el-table-column prop="age" label="年龄" sortable width="100" />
<el-table-column prop="address" label="地址" show-overflow-tooltip />
<el-table-column label="操作" width="160">
<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>
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
background
@size-change="fetchData"
@current-change="fetchData"
class="mt-4 justify-end"
/>
</div>
</template>