202 lines
6.2 KiB
Markdown
202 lines
6.2 KiB
Markdown
---
|
||
title: Element Plus 表格组件
|
||
date: 2026-05-27
|
||
---
|
||
|
||
# 一、加载中
|
||
```vue
|
||
<el-table
|
||
v-loading="dispatchStore.isLoading"
|
||
element-loading-text="加载中..."
|
||
:data="dispatchStore.contractList"
|
||
border
|
||
stripeempty-text="暂无记录"
|
||
class="common-table">
|
||
|
||
</el-table>
|
||
```
|
||
|
||
::: tip
|
||
要配合pinia存储使用,获取数据前将loading置为true,完成后置为false。
|
||
:::
|
||
|
||
# 二、展开行
|
||
```vue
|
||
<template>
|
||
<el-table :data="dispatchStore.contractList"
|
||
:row-key="getRowKey"
|
||
:expand-row-keys="expandedRows"
|
||
@expand-change="handleExpandChange">
|
||
<el-table-column type="expand">
|
||
<template #default="props">
|
||
<el-table :data="props.row.dispatchList"
|
||
border stripeempty-text="暂无记录"
|
||
class="dispatch-content"
|
||
style="width: 100%">
|
||
<el-table-column fixed type="index" align="center" width="60" />
|
||
<el-table-column prop="customer" label="终端客户" align="center" width="180"/>
|
||
</el-table>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
const expandedRows = ref<number[]>([])
|
||
|
||
// 获取行的唯一标识
|
||
const getRowKey = (row: IDispatch) => {
|
||
return row.id
|
||
}
|
||
|
||
// 处理展开行变化
|
||
const handleExpandChange = (row: IDispatch, expandedRowsList: IDispatch[]) => {
|
||
if (expandedRowsList.length > 0) {
|
||
// 只保留最新展开的行
|
||
expandedRows.value = [getRowKey(row)]
|
||
} else {
|
||
expandedRows.value = []
|
||
}
|
||
}
|
||
</script>
|
||
```
|
||
|
||
  通过类型expand和插槽props实现,可以展示任意格式数据。
|
||
  增加表格的`row-key`、`expand-row-key`属性可以实现只展开某一行功能。
|
||
|
||
# 三、排序和筛选
|
||
```vue
|
||
<template>
|
||
<el-table :data="dispatchStore.contractList">
|
||
<el-table-column prop="contractNum" label="合同编号" align="center" min-width="10%"
|
||
:filters=contractNumFilters :filter-method="filterColumnMethod" sortable>
|
||
</el-table-column>
|
||
</el-table>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { useDispatchStore } from '@/stores/dispatch.ts'
|
||
import { computed } from 'vue'
|
||
import type { IContract } from '@/types/dispatch.ts'
|
||
|
||
const dispatchStore = useDispatchStore()
|
||
|
||
type ContractField = keyof IContract
|
||
|
||
const filterColumnMethod = (value, row, column) => {
|
||
return row[column.property] === value
|
||
}
|
||
|
||
const getFiltersByKey = (key: ContractField) => {
|
||
const result = [...new Set(dispatchStore.contractList.map((item) => item[key]).filter((value) => value != null && value !==''))]
|
||
|
||
return result.map((item) => ({
|
||
text: item,
|
||
value: item
|
||
}))
|
||
}
|
||
|
||
const contractNumFilters = computed(() => getFiltersByKey('contractNum'))
|
||
</script>
|
||
```
|
||
|
||
  在`el-table-column`中添加`sortable`即可实现排序功能。
|
||
  在`el-table-column`中添加`filters`和`filter-method`实现筛选功能。
|
||
  `filters`为原始数据中该字段下的所有值,并转为指定格式,也可以自定义筛选字段。
|
||
|
||
# 四、表头搜索
|
||
```vue
|
||
<template>
|
||
<el-table :data="dispatchStore.contractList" >
|
||
<el-table-column prop="contractNum" label="合同编号" align="center" min-width="10%">
|
||
<template #header>
|
||
<div class="custom-header">
|
||
<span :class="{ 'active': contractNumSearch }">合同编号</span>
|
||
<el-popover ref="contractNumPopoverRef" placement="bottom" width="230" trigger="click">
|
||
<template #default>
|
||
<el-select v-model="contractNumSearch" filterable clearable
|
||
placeholder="请选择或输入合同编号" @change="applySearch('contractNum')">
|
||
<el-option v-for="(item, index) in contractNumValue"
|
||
:key="index" :label="item" :value="item"/>
|
||
</el-select>
|
||
<div style="margin-top: 8px;display: flex;justify-content: flex-end;">
|
||
<el-button type="primary" size="small" @click="applySearch('contractNum')">搜索</el-button>
|
||
<el-button size="small" @click="resetSearch('contractNum')">重置</el-button>
|
||
</div>
|
||
</template>
|
||
<template #reference>
|
||
<el-icon class="search-icon"><Search/></el-icon>
|
||
</template>
|
||
</el-popover>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { useDispatchStore } from '@/stores/dispatch.ts'
|
||
import { computed, ref } from 'vue'
|
||
import { Search } from '@element-plus/icons-vue'
|
||
import type { IContract } from '@/types/dispatch.ts'
|
||
import type { PopoverInstance } from 'element-plus'
|
||
import type { Ref } from 'vue'
|
||
|
||
const dispatchStore = useDispatchStore()
|
||
|
||
type ContractField = keyof IContract
|
||
|
||
const getFiltersByKey = (key: ContractField) => {
|
||
const result = [...new Set(dispatchStore.contractList.map((item) => item[key]).filter((value) => value != null && value !== ''))]
|
||
|
||
return result.map((item) => ({
|
||
text: item,
|
||
value: item
|
||
}))
|
||
}
|
||
|
||
const contractNumFilters = computed(() => getFiltersByKey('contractNum'))
|
||
|
||
const contractNumValue = computed(() => contractNumFilters.value.map((item) => item.value))
|
||
|
||
const contractNumPopoverRef = ref<PopoverInstance>()
|
||
const contractNumSearch = ref('')
|
||
|
||
const popoverMap = new Map<string, Ref<PopoverInstance | undefined>>([
|
||
['contractNum', contractNumPopoverRef]
|
||
])
|
||
const searchMap = new Map<string, Ref<string>>([
|
||
['contractNum', contractNumSearch]
|
||
])
|
||
|
||
const applySearch = async (field: ContractField) => {
|
||
const searchRef = searchMap.get(field)
|
||
|
||
if (!searchRef) return
|
||
|
||
if (!searchRef.value) {
|
||
await dispatchStore.queryContractList()
|
||
return
|
||
}
|
||
if (!searchRef.value.trim()) return
|
||
|
||
dispatchStore.contractList = dispatchStore.contractList.filter((item) => {
|
||
const value = item[field]
|
||
return typeof value === 'string' && value.includes(searchRef.value)
|
||
})
|
||
popoverMap.get(field)?.value?.hide()
|
||
}
|
||
|
||
const resetSearch = async (field: string) => {
|
||
const searchRef = searchMap.get(field)
|
||
|
||
if (searchRef) {
|
||
searchRef.value = ''
|
||
}
|
||
popoverMap.get(field)?.value?.hide()
|
||
await dispatchStore.queryContractList()
|
||
}
|
||
</script>
|
||
```
|
||
|
||
  表头搜索主要利用`header`插槽和`el-popover`组件实现。 |