feat(components): [table-column] add filter-icon slot (#17272)

* feat(components): [table] add `filter-icon` prop

* chore: remove

* chore: remove

* Update docs/en-US/component/table.md

* feat: filter-icon slot

* test: test case

* chore: update

* chore: update
This commit is contained in:
btea 2024-07-24 14:47:42 +08:00 committed by GitHub
parent 06ab1a0183
commit c7dea71e81
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 112 additions and 13 deletions

View File

@ -371,10 +371,11 @@ table/table-layout
### Table-column Slots ### Table-column Slots
| Name | Description | Type | | Name | Description | Type |
| ------- | -------------------------------- | ---------------------------------------------------- | | -------------------- | -------------------------------- | ---------------------------------------------------- |
| default | Custom content for table columns | ^[object]`{ row: any, column: any, $index: number }` | | default | Custom content for table columns | ^[object]`{ row: any, column: any, $index: number }` |
| header | Custom content for table header | ^[object]`{ column: any, $index: number }` | | header | Custom content for table header | ^[object]`{ column: any, $index: number }` |
| filter-icon ^(2.7.8) | Custom content for filter icon | ^[object]`{ filterOpened: boolean }` |
## Type Declarations ## Type Declarations

View File

@ -4,6 +4,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import ElCheckbox from '@element-plus/components/checkbox' import ElCheckbox from '@element-plus/components/checkbox'
import triggerEvent from '@element-plus/test-utils/trigger-event' import triggerEvent from '@element-plus/test-utils/trigger-event'
import { rAF } from '@element-plus/test-utils/tick' import { rAF } from '@element-plus/test-utils/tick'
import { CaretBottom, CaretTop } from '@element-plus/icons-vue'
import ElTable from '../src/table.vue' import ElTable from '../src/table.vue'
import ElTableColumn from '../src/table-column' import ElTableColumn from '../src/table-column'
import { import {
@ -439,6 +440,84 @@ describe('Table.vue', () => {
}) })
}) })
describe('filter filter-icon slot', () => {
let wrapper: VueWrapper<ComponentPublicInstance>
beforeEach(async () => {
wrapper = mount({
components: {
ElTable,
ElTableColumn,
CaretBottom,
CaretTop,
},
template: `
<el-table ref="table" :data="testData" @filter-change="handleFilterChange">
<el-table-column prop="name" label="片名" />
<el-table-column prop="release" label="发行日期" />
<el-table-column
prop="director"
column-key="director"
:filters="[
{ text: 'John Lasseter', value: 'John Lasseter' },
{ text: 'Peter Docter', value: 'Peter Docter' },
{ text: 'Andrew Stanton', value: 'Andrew Stanton' }
]"
:filter-method="filterMethod"
label="导演">
<template #filter-icon="{ filterOpened }">
<CaretTop v-if="filterOpened" class="top" />
<CaretBottom v-else class="bottom" />
</template>
</el-table-column>
<el-table-column prop="runtime" label="时长(分)" />
</el-table>
`,
created() {
this.testData = getTestData()
},
methods: {
filterMethod(value, row) {
return value === row.director
},
handleFilterChange(filters) {
this.filters = filters
},
},
})
await doubleWait()
})
afterEach(() => wrapper.unmount())
it('render', () => {
expect(
wrapper.find('.el-table__column-filter-trigger')
).not.toBeUndefined()
expect(
wrapper.find('.el-table__column-filter-trigger .bottom')
).not.toBeUndefined()
})
it('click filter-trigger', async () => {
const btn = wrapper.find('.el-table__column-filter-trigger')
btn.trigger('click')
await doubleWait()
expect(
wrapper.find('.el-table__column-filter-trigger .top')
).not.toBeUndefined()
btn.trigger('click')
await doubleWait()
expect(
wrapper.find('.el-table__column-filter-trigger .bottom')
).not.toBeUndefined()
})
})
describe('events', () => { describe('events', () => {
const createTable = function (prop = '') { const createTable = function (prop = '') {
return mount({ return mount({

View File

@ -78,8 +78,10 @@
@click="showFilterPanel" @click="showFilterPanel"
> >
<el-icon> <el-icon>
<arrow-up v-if="column.filterOpened" /> <slot name="filter-icon">
<arrow-down v-else /> <arrow-up v-if="column.filterOpened" />
<arrow-down v-else />
</slot>
</el-icon> </el-icon>
</span> </span>
</template> </template>

View File

@ -124,6 +124,12 @@ function useRender<T>(
} }
} }
if (slots['filter-icon']) {
column.renderFilterIcon = (scope) => {
return renderSlot(slots, 'filter-icon', scope)
}
}
let originRenderCell = column.renderCell let originRenderCell = column.renderCell
// TODO: 这里的实现调整 // TODO: 这里的实现调整
if (column.type === 'expand') { if (column.type === 'expand') {

View File

@ -224,14 +224,25 @@ export default defineComponent({
] ]
), ),
column.filterable && column.filterable &&
h(FilterPanel, { h(
store, FilterPanel,
placement: column.filterPlacement || 'bottom-start', {
column, store,
upDataColumn: (key, value) => { placement: column.filterPlacement || 'bottom-start',
column[key] = value column,
upDataColumn: (key, value) => {
column[key] = value
},
}, },
}), {
'filter-icon': () =>
column.renderFilterIcon
? column.renderFilterIcon({
filterOpened: column.filterOpened,
})
: null,
}
),
] ]
), ),
] ]