refactor: table
parent
8d60808662
commit
10cb279dfc
|
@ -164,6 +164,14 @@ export { default as Steps, Step } from './steps';
|
|||
export type { SwitchProps } from './switch';
|
||||
export { default as Switch } from './switch';
|
||||
|
||||
export type {
|
||||
TableProps,
|
||||
TablePaginationConfig,
|
||||
ColumnGroupType as TableColumnGroupType,
|
||||
ColumnType as TableColumnType,
|
||||
ColumnProps as TableColumnProps,
|
||||
ColumnsType as TableColumnsType,
|
||||
} from './table';
|
||||
export { default as Table, TableColumn, TableColumnGroup } from './table';
|
||||
|
||||
export type { TransferProps } from './transfer';
|
||||
|
|
|
@ -51,6 +51,7 @@ import classNames from '../_util/classNames';
|
|||
import omit from '../_util/omit';
|
||||
import { initDefaultProps } from '../_util/props-util';
|
||||
import { ContextSlots, useProvideSlots } from './context';
|
||||
import useColumns from './hooks/useColumns';
|
||||
|
||||
export type { ColumnsType, TablePaginationConfig };
|
||||
|
||||
|
@ -107,7 +108,7 @@ export interface TableProps<RecordType = DefaultRecordType>
|
|||
sortDirections?: SortOrder[];
|
||||
showSorterTooltip?: boolean | TooltipProps;
|
||||
}
|
||||
const tableProps = () => {
|
||||
export const tableProps = () => {
|
||||
return {
|
||||
prefixCls: { type: String as PropType<string>, default: undefined },
|
||||
columns: { type: Array as PropType<ColumnsType>, default: undefined },
|
||||
|
@ -394,10 +395,13 @@ const InteralTable = defineComponent<
|
|||
});
|
||||
const mergedData = computed(() => getFilterData(sortedData.value, filterStates.value));
|
||||
// ============================ Column ============================
|
||||
|
||||
const [transformBasicColumns] = useColumns(toRef(props, 'contextSlots'));
|
||||
|
||||
const columnTitleProps = computed(() => ({
|
||||
...sorterTitleProps.value,
|
||||
}));
|
||||
const [transformTitleColumns] = useTitleColumns(columnTitleProps, toRef(props, 'contextSlots'));
|
||||
const [transformTitleColumns] = useTitleColumns(columnTitleProps);
|
||||
|
||||
// ========================== Pagination ==========================
|
||||
const onPaginationChange = (current: number, pageSize: number) => {
|
||||
|
@ -505,7 +509,9 @@ const InteralTable = defineComponent<
|
|||
|
||||
const transformColumns = (innerColumns: ColumnsType<any>): ColumnsType<any> => {
|
||||
const res = transformTitleColumns(
|
||||
transformSelectionColumns(transformFilterColumns(transformSorterColumns(innerColumns))),
|
||||
transformSelectionColumns(
|
||||
transformFilterColumns(transformSorterColumns(transformBasicColumns(innerColumns))),
|
||||
),
|
||||
);
|
||||
return res;
|
||||
};
|
||||
|
|
|
@ -28,11 +28,14 @@ This example shows how to fetch and present data from a remote server, and how t
|
|||
:loading="loading"
|
||||
@change="handleTableChange"
|
||||
>
|
||||
<template #name="{ text }">{{ text.first }} {{ text.last }}</template>
|
||||
<template #bodyCell="{ column, text }">
|
||||
<template v-if="column.dataIndex === 'name'">{{ text.first }} {{ text.last }}</template>
|
||||
<template v-else>{{ text }}</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { TableState, TableStateFilters } from 'ant-design-vue/es/table/interface';
|
||||
import type { TableProps } from 'ant-design-vue';
|
||||
import { usePagination } from 'vue-request';
|
||||
import { computed, defineComponent } from 'vue';
|
||||
const columns = [
|
||||
|
@ -41,7 +44,6 @@ const columns = [
|
|||
dataIndex: 'name',
|
||||
sorter: true,
|
||||
width: '20%',
|
||||
slots: { customRender: 'name' },
|
||||
},
|
||||
{
|
||||
title: 'Gender',
|
||||
|
@ -58,7 +60,6 @@ const columns = [
|
|||
},
|
||||
];
|
||||
|
||||
type Pagination = TableState['pagination'];
|
||||
type APIParams = {
|
||||
results: number;
|
||||
page?: number;
|
||||
|
@ -80,16 +81,19 @@ const queryData = (params: APIParams) => {
|
|||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const { data: dataSource, run, loading, current, pageSize } = usePagination<APIResult>(
|
||||
queryData,
|
||||
{
|
||||
const {
|
||||
data: dataSource,
|
||||
run,
|
||||
loading,
|
||||
current,
|
||||
pageSize,
|
||||
} = usePagination<APIResult>(queryData, {
|
||||
formatResult: res => res.results,
|
||||
pagination: {
|
||||
currentKey: 'page',
|
||||
pageSizeKey: 'results',
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
const pagination = computed(() => ({
|
||||
total: 200,
|
||||
|
@ -97,9 +101,13 @@ export default defineComponent({
|
|||
pageSize: pageSize.value,
|
||||
}));
|
||||
|
||||
const handleTableChange = (pag: Pagination, filters: TableStateFilters, sorter: any) => {
|
||||
const handleTableChange: TableProps['onChange'] = (
|
||||
pag: { pageSize: number; current: number },
|
||||
filters: any,
|
||||
sorter: any,
|
||||
) => {
|
||||
run({
|
||||
results: pag!.pageSize!,
|
||||
results: pag.pageSize!,
|
||||
page: pag?.current,
|
||||
sortField: sorter.field,
|
||||
sortOrder: sorter.order,
|
||||
|
|
|
@ -17,9 +17,12 @@ Add border, title and footer for table.
|
|||
|
||||
<template>
|
||||
<a-table :columns="columns" :data-source="data" bordered>
|
||||
<template #name="{ text }">
|
||||
<template #bodyCell="{ column, text }">
|
||||
<template v-if="column.dataIndex === 'name'">
|
||||
<a>{{ text }}</a>
|
||||
</template>
|
||||
<template v-else>{{ text }}</template>
|
||||
</template>
|
||||
<template #title>Header</template>
|
||||
<template #footer>Footer</template>
|
||||
</a-table>
|
||||
|
@ -31,7 +34,6 @@ const columns = [
|
|||
{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
slots: { customRender: 'name' },
|
||||
},
|
||||
{
|
||||
title: 'Cash Assets',
|
||||
|
|
|
@ -20,19 +20,21 @@ Table cell supports `colSpan` and `rowSpan` that set in render return object. Wh
|
|||
|
||||
<template>
|
||||
<a-table :columns="columns" :data-source="data" bordered>
|
||||
<template #name="{ text }">
|
||||
<a>{{ text }}</a>
|
||||
<template #bodyCell="{ column, text }">
|
||||
<template v-if="column.dataIndex === 'name'">
|
||||
<a href="javascript:;">{{ text }}</a>
|
||||
</template>
|
||||
<template v-else>{{ text }}</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, h } from 'vue';
|
||||
import { ColumnProps } from 'ant-design-vue/es/table/interface';
|
||||
import { defineComponent } from 'vue';
|
||||
import { TableColumnType } from 'ant-design-vue';
|
||||
// In the fifth row, other columns are merged into first column
|
||||
// by setting it's colSpan to be 0
|
||||
const renderContent = ({ text, index }: any) => {
|
||||
const renderContent = ({ index }: any) => {
|
||||
const obj = {
|
||||
children: text,
|
||||
props: {} as any,
|
||||
};
|
||||
if (index === 4) {
|
||||
|
@ -86,16 +88,15 @@ const data = [
|
|||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const columns: ColumnProps[] = [
|
||||
const columns: TableColumnType[] = [
|
||||
{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
customRender: ({ text, index }) => {
|
||||
customRender: ({ index }) => {
|
||||
if (index < 4) {
|
||||
return h('a', { href: 'javascript:;' }, text);
|
||||
return;
|
||||
}
|
||||
return {
|
||||
children: h('a', { href: 'javascript:;' }, text),
|
||||
props: {
|
||||
colSpan: 5,
|
||||
},
|
||||
|
@ -111,9 +112,8 @@ export default defineComponent({
|
|||
title: 'Home phone',
|
||||
colSpan: 2,
|
||||
dataIndex: 'tel',
|
||||
customRender: ({ text, index }) => {
|
||||
customRender: ({ index }) => {
|
||||
const obj = {
|
||||
children: text,
|
||||
props: {} as any,
|
||||
};
|
||||
if (index === 2) {
|
||||
|
|
|
@ -8,17 +8,25 @@ title:
|
|||
|
||||
## zh-CN
|
||||
|
||||
通过 `filterDropdown` 定义自定义的列筛选功能,并实现一个搜索列的示例。
|
||||
通过 `customFilterDropdown` 定义自定义的列筛选功能,并实现一个搜索列的示例。
|
||||
|
||||
## en-US
|
||||
|
||||
Implement a customized column search example via `filterDropdown`.
|
||||
Implement a customized column search example via `customFilterDropdown`.
|
||||
|
||||
</docs>
|
||||
|
||||
<template>
|
||||
<a-table :data-source="data" :columns="columns">
|
||||
<template #filterDropdown="{ setSelectedKeys, selectedKeys, confirm, clearFilters, column }">
|
||||
<template #headerCell="{ column }">
|
||||
<template v-if="column.key === 'name'">
|
||||
<span style="color: #1890ff">Name</span>
|
||||
</template>
|
||||
<template v-else>{{ column.title }}</template>
|
||||
</template>
|
||||
<template
|
||||
#customFilterDropdown="{ setSelectedKeys, selectedKeys, confirm, clearFilters, column }"
|
||||
>
|
||||
<div style="padding: 8px">
|
||||
<a-input
|
||||
ref="searchInput"
|
||||
|
@ -42,11 +50,12 @@ Implement a customized column search example via `filterDropdown`.
|
|||
</a-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #filterIcon="filtered">
|
||||
<template #customFilterIcon="{ filtered }">
|
||||
<search-outlined :style="{ color: filtered ? '#108ee9' : undefined }" />
|
||||
</template>
|
||||
<template #customRender="{ text, column }">
|
||||
<template #bodyCell="{ text, column }">
|
||||
<span v-if="searchText && searchedColumn === column.dataIndex">
|
||||
{{ searchText }}{{ searchedColumn }} {{ column.dataIndex }}
|
||||
<template
|
||||
v-for="(fragment, i) in text
|
||||
.toString()
|
||||
|
@ -116,17 +125,12 @@ export default defineComponent({
|
|||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
slots: {
|
||||
filterDropdown: 'filterDropdown',
|
||||
filterIcon: 'filterIcon',
|
||||
customRender: 'customRender',
|
||||
},
|
||||
customFilterDropdown: true,
|
||||
onFilter: (value, record) =>
|
||||
record.name.toString().toLowerCase().includes(value.toLowerCase()),
|
||||
onFilterDropdownVisibleChange: visible => {
|
||||
if (visible) {
|
||||
setTimeout(() => {
|
||||
console.log(searchInput.value);
|
||||
searchInput.value.focus();
|
||||
}, 100);
|
||||
}
|
||||
|
@ -136,30 +140,12 @@ export default defineComponent({
|
|||
title: 'Age',
|
||||
dataIndex: 'age',
|
||||
key: 'age',
|
||||
slots: {
|
||||
filterDropdown: 'filterDropdown',
|
||||
filterIcon: 'filterIcon',
|
||||
customRender: 'customRender',
|
||||
},
|
||||
onFilter: (value, record) =>
|
||||
record.age.toString().toLowerCase().includes(value.toLowerCase()),
|
||||
onFilterDropdownVisibleChange: visible => {
|
||||
if (visible) {
|
||||
setTimeout(() => {
|
||||
searchInput.value.focus();
|
||||
}, 100);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Address',
|
||||
dataIndex: 'address',
|
||||
key: 'address',
|
||||
slots: {
|
||||
filterDropdown: 'filterDropdown',
|
||||
filterIcon: 'filterIcon',
|
||||
customRender: 'customRender',
|
||||
},
|
||||
customFilterDropdown: true,
|
||||
onFilter: (value, record) =>
|
||||
record.address.toString().toLowerCase().includes(value.toLowerCase()),
|
||||
onFilterDropdownVisibleChange: visible => {
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import devWarning from '../../vc-util/devWarning';
|
||||
import type { Ref } from 'vue';
|
||||
import { ContextSlots } from '../context';
|
||||
import type { TransformColumns, ColumnsType } from '../interface';
|
||||
|
||||
function fillSlots<RecordType>(columns: ColumnsType<RecordType>, contextSlots: Ref<ContextSlots>) {
|
||||
const $slots = contextSlots.value;
|
||||
return columns.map(column => {
|
||||
const cloneColumn = { ...column };
|
||||
const { slots = {} } = cloneColumn;
|
||||
cloneColumn.__originColumn__ = column;
|
||||
devWarning(
|
||||
!('slots' in cloneColumn),
|
||||
'Table',
|
||||
'`column.slots` is deprecated. Please use `v-slot:headerCell` `v-slot:bodyCell` instead.',
|
||||
);
|
||||
|
||||
Object.keys(slots).forEach(key => {
|
||||
const name = slots[key];
|
||||
if (cloneColumn[key] === undefined && $slots[name]) {
|
||||
cloneColumn[key] = $slots[name];
|
||||
}
|
||||
});
|
||||
|
||||
if (contextSlots.value.headerCell && !column.slots?.title) {
|
||||
cloneColumn.title = contextSlots.value.headerCell({
|
||||
title: column.title,
|
||||
column,
|
||||
});
|
||||
}
|
||||
if ('children' in cloneColumn) {
|
||||
cloneColumn.children = fillSlots(cloneColumn.children, contextSlots);
|
||||
}
|
||||
|
||||
return cloneColumn;
|
||||
});
|
||||
}
|
||||
|
||||
export default function useColumns<RecordType>(
|
||||
contextSlots: Ref<ContextSlots>,
|
||||
): [TransformColumns<RecordType>] {
|
||||
const filledColumns = (columns: ColumnsType<RecordType>) => fillSlots(columns, contextSlots);
|
||||
|
||||
return [filledColumns];
|
||||
}
|
|
@ -15,7 +15,7 @@ import type {
|
|||
} from '../../interface';
|
||||
import FilterDropdownMenuWrapper from './FilterWrapper';
|
||||
import type { FilterState } from '.';
|
||||
import { computed, defineComponent, onBeforeUnmount, ref } from 'vue';
|
||||
import { computed, defineComponent, nextTick, onBeforeUnmount, ref, watch } from 'vue';
|
||||
import classNames from '../../../_util/classNames';
|
||||
import useConfigInject from '../../../_util/hooks/useConfigInject';
|
||||
import { useInjectSlots } from '../../context';
|
||||
|
@ -131,6 +131,24 @@ export default defineComponent<FilterDropdownProps<any>>({
|
|||
),
|
||||
);
|
||||
|
||||
const filterDropdownRef = computed(() => {
|
||||
const { filterDropdown, slots = {}, customFilterDropdown } = props.column;
|
||||
return (
|
||||
filterDropdown ||
|
||||
(slots.filterDropdown && contextSlots.value[slots.filterDropdown]) ||
|
||||
(customFilterDropdown && contextSlots.value.customFilterDropdown)
|
||||
);
|
||||
});
|
||||
|
||||
const filterIconRef = computed(() => {
|
||||
const { filterIcon, slots = {} } = props.column;
|
||||
return (
|
||||
filterIcon ||
|
||||
(slots.filterIcon && contextSlots.value[slots.filterIcon]) ||
|
||||
contextSlots.value.customFilterIcon
|
||||
);
|
||||
});
|
||||
|
||||
const triggerVisible = (newVisible: boolean) => {
|
||||
visible.value = newVisible;
|
||||
props.column.onFilterDropdownVisibleChange?.(newVisible);
|
||||
|
@ -142,16 +160,22 @@ export default defineComponent<FilterDropdownProps<any>>({
|
|||
: visible.value,
|
||||
);
|
||||
|
||||
const filteredKeys = ref([]);
|
||||
const propFilteredKeys = computed(() => props.filterState?.filteredKeys);
|
||||
|
||||
const mergedFilteredKeys = computed(
|
||||
() => props.filterState?.filteredKeys || filteredKeys.value || [],
|
||||
);
|
||||
const filteredKeys = ref([]);
|
||||
|
||||
const onSelectKeys = ({ selectedKeys }: { selectedKeys?: Key[] }) => {
|
||||
filteredKeys.value = selectedKeys;
|
||||
};
|
||||
|
||||
watch(
|
||||
propFilteredKeys,
|
||||
() => {
|
||||
onSelectKeys({ selectedKeys: propFilteredKeys.value || [] });
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
const openKeys = ref([]);
|
||||
|
||||
const openRef = ref();
|
||||
|
@ -190,7 +214,7 @@ export default defineComponent<FilterDropdownProps<any>>({
|
|||
|
||||
const onConfirm = () => {
|
||||
triggerVisible(false);
|
||||
internalTriggerFilter(mergedFilteredKeys.value);
|
||||
internalTriggerFilter(filteredKeys.value);
|
||||
};
|
||||
|
||||
const onReset = () => {
|
||||
|
@ -203,14 +227,18 @@ export default defineComponent<FilterDropdownProps<any>>({
|
|||
if (closeDropdown) {
|
||||
triggerVisible(false);
|
||||
}
|
||||
internalTriggerFilter(mergedFilteredKeys.value);
|
||||
internalTriggerFilter(filteredKeys.value);
|
||||
};
|
||||
|
||||
const onVisibleChange = (newVisible: boolean) => {
|
||||
if (newVisible && propFilteredKeys.value !== undefined) {
|
||||
// Sync filteredKeys on appear in controlled mode (propFilteredKeys.value !== undefiend)
|
||||
filteredKeys.value = propFilteredKeys.value || [];
|
||||
}
|
||||
triggerVisible(newVisible);
|
||||
|
||||
// Default will filter when closed
|
||||
if (!newVisible && !props.column.filterDropdown) {
|
||||
if (!newVisible && !filterDropdownRef.value) {
|
||||
onConfirm();
|
||||
}
|
||||
};
|
||||
|
@ -233,20 +261,21 @@ export default defineComponent<FilterDropdownProps<any>>({
|
|||
|
||||
let dropdownContent;
|
||||
|
||||
if (typeof column.filterDropdown === 'function') {
|
||||
dropdownContent = column.filterDropdown({
|
||||
if (typeof filterDropdownRef.value === 'function') {
|
||||
dropdownContent = filterDropdownRef.value({
|
||||
prefixCls: `${dropdownPrefixCls}-custom`,
|
||||
setSelectedKeys: (selectedKeys: Key[]) => onSelectKeys({ selectedKeys }),
|
||||
selectedKeys: mergedFilteredKeys.value,
|
||||
selectedKeys: filteredKeys.value,
|
||||
confirm: doFilter,
|
||||
clearFilters: onReset,
|
||||
filters: column.filters,
|
||||
visible: mergedVisible.value,
|
||||
column: column.__originColumn__,
|
||||
});
|
||||
} else if (column.filterDropdown) {
|
||||
dropdownContent = column.filterDropdown;
|
||||
} else if (filterDropdownRef.value) {
|
||||
dropdownContent = filterDropdownRef.value;
|
||||
} else {
|
||||
const selectedKeys = mergedFilteredKeys.value as any;
|
||||
const selectedKeys = filteredKeys.value as any;
|
||||
dropdownContent = (
|
||||
<>
|
||||
<Menu
|
||||
|
@ -265,7 +294,7 @@ export default defineComponent<FilterDropdownProps<any>>({
|
|||
renderFilterItems({
|
||||
filters: column.filters || [],
|
||||
prefixCls,
|
||||
filteredKeys: mergedFilteredKeys.value,
|
||||
filteredKeys: filteredKeys.value,
|
||||
filterMultiple,
|
||||
locale,
|
||||
}),
|
||||
|
@ -295,19 +324,20 @@ export default defineComponent<FilterDropdownProps<any>>({
|
|||
);
|
||||
|
||||
let filterIcon;
|
||||
if (typeof column.filterIcon === 'function') {
|
||||
filterIcon = column.filterIcon({ filtered: filtered.value, column });
|
||||
} else if (column.filterIcon) {
|
||||
filterIcon = column.filterIcon;
|
||||
} else if (contextSlots.value.customFilterIcon) {
|
||||
filterIcon = contextSlots.value.customFilterIcon({ filtered: filtered.value, column });
|
||||
if (typeof filterIconRef.value === 'function') {
|
||||
filterIcon = filterIconRef.value({
|
||||
filtered: filtered.value,
|
||||
column: column.__originColumn__,
|
||||
});
|
||||
} else if (filterIconRef.value) {
|
||||
filterIcon = filterIconRef.value;
|
||||
} else {
|
||||
filterIcon = <FilterFilled />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={`${prefixCls}-column`}>
|
||||
<span class={`${tablePrefixCls}-column-title`}>{slots.defalut?.()}</span>
|
||||
<span class={`${tablePrefixCls}-column-title`}>{slots.default?.()}</span>
|
||||
<Dropdown
|
||||
overlay={menu}
|
||||
trigger={['click']}
|
||||
|
|
|
@ -34,14 +34,13 @@ function collectFilterStates<RecordType>(
|
|||
|
||||
(columns || []).forEach((column, index) => {
|
||||
const columnPos = getColumnPos(index, pos);
|
||||
|
||||
if ('children' in column) {
|
||||
filterStates = [...filterStates, ...collectFilterStates(column.children, init, columnPos)];
|
||||
} else if (column.filters || 'filterDropdown' in column || 'onFilter' in column) {
|
||||
const hasFilterDropdown =
|
||||
column.filterDropdown || column?.slots?.filterDropdown || column.customFilterDropdown;
|
||||
if (column.filters || hasFilterDropdown || 'onFilter' in column) {
|
||||
if ('filteredValue' in column) {
|
||||
// Controlled
|
||||
let filteredValues = column.filteredValue;
|
||||
if (!('filterDropdown' in column)) {
|
||||
if (!hasFilterDropdown) {
|
||||
filteredValues = filteredValues?.map(String) ?? filteredValues;
|
||||
}
|
||||
filterStates.push({
|
||||
|
@ -62,6 +61,9 @@ function collectFilterStates<RecordType>(
|
|||
});
|
||||
}
|
||||
}
|
||||
if ('children' in column) {
|
||||
filterStates = [...filterStates, ...collectFilterStates(column.children, init, columnPos)];
|
||||
}
|
||||
});
|
||||
|
||||
return filterStates;
|
||||
|
@ -82,8 +84,9 @@ function injectFilter<RecordType>(
|
|||
const { filterMultiple = true } = column as ColumnType<RecordType>;
|
||||
|
||||
let newColumn: ColumnsType<RecordType>[number] = column;
|
||||
|
||||
if (newColumn.filters || newColumn.filterDropdown) {
|
||||
const hasFilterDropdown =
|
||||
column.filterDropdown || column?.slots?.filterDropdown || column.customFilterDropdown;
|
||||
if (newColumn.filters || hasFilterDropdown) {
|
||||
const columnKey = getColumnKey(newColumn, columnPos);
|
||||
const filterState = filterStates.find(({ key }) => columnKey === key);
|
||||
|
||||
|
@ -143,9 +146,10 @@ function generateFilterInfo<RecordType>(filterStates: FilterState<RecordType>[])
|
|||
const currentFilters: Record<string, FilterValue | null> = {};
|
||||
|
||||
filterStates.forEach(({ key, filteredKeys, column }) => {
|
||||
console.log(column);
|
||||
const { filters, filterDropdown } = column;
|
||||
if (filterDropdown) {
|
||||
const hasFilterDropdown =
|
||||
column.filterDropdown || column?.slots?.filterDropdown || column.customFilterDropdown;
|
||||
const { filters } = column;
|
||||
if (hasFilterDropdown) {
|
||||
currentFilters[key] = filteredKeys || null;
|
||||
} else if (Array.isArray(filteredKeys)) {
|
||||
const keys = flattenKeys(filters);
|
||||
|
|
|
@ -1,35 +1,18 @@
|
|||
import devWarning from '../../vc-util/devWarning';
|
||||
import type { Ref } from 'vue';
|
||||
import { ContextSlots } from '../context';
|
||||
import type { TransformColumns, ColumnTitleProps, ColumnsType } from '../interface';
|
||||
import { renderColumnTitle } from '../util';
|
||||
|
||||
function fillTitle<RecordType>(
|
||||
columns: ColumnsType<RecordType>,
|
||||
columnTitleProps: ColumnTitleProps<RecordType>,
|
||||
contextColumns: Ref<ContextSlots>,
|
||||
) {
|
||||
const $slots = contextColumns.value;
|
||||
return columns.map(column => {
|
||||
const cloneColumn = { ...column };
|
||||
const { slots = {} } = cloneColumn;
|
||||
|
||||
devWarning(
|
||||
!('slots' in cloneColumn),
|
||||
'Table',
|
||||
'`column.slots` is deprecated. Please use `v-slot:headerCell` `v-slot:bodyCell` instead.',
|
||||
);
|
||||
|
||||
Object.keys(slots).forEach(key => {
|
||||
const name = slots[key];
|
||||
if (cloneColumn[key] === undefined && $slots[name]) {
|
||||
cloneColumn[key] = $slots[name];
|
||||
}
|
||||
});
|
||||
cloneColumn.title = renderColumnTitle(cloneColumn.title, columnTitleProps);
|
||||
|
||||
if ('children' in cloneColumn) {
|
||||
cloneColumn.children = fillTitle(cloneColumn.children, columnTitleProps, contextColumns);
|
||||
cloneColumn.children = fillTitle(cloneColumn.children, columnTitleProps);
|
||||
}
|
||||
|
||||
return cloneColumn;
|
||||
|
@ -38,10 +21,9 @@ function fillTitle<RecordType>(
|
|||
|
||||
export default function useTitleColumns<RecordType>(
|
||||
columnTitleProps: Ref<ColumnTitleProps<RecordType>>,
|
||||
contextColumns: Ref<ContextSlots>,
|
||||
): [TransformColumns<RecordType>] {
|
||||
const filledColumns = (columns: ColumnsType<RecordType>) =>
|
||||
fillTitle(columns, columnTitleProps.value, contextColumns);
|
||||
fillTitle(columns, columnTitleProps.value);
|
||||
|
||||
return [filledColumns];
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import Table from './Table';
|
||||
import Table, { tableProps } from './Table';
|
||||
import type Column from './Column';
|
||||
import type ColumnGroup from './ColumnGroup';
|
||||
import type { TableProps, TablePaginationConfig } from './Table';
|
||||
|
@ -18,6 +18,7 @@ Table.install = function (app: App) {
|
|||
|
||||
export const TableColumn = Table.Column;
|
||||
export const TableColumnGroup = Table.ColumnGroup;
|
||||
export { tableProps };
|
||||
|
||||
export default Table as typeof Table &
|
||||
Plugin & {
|
||||
|
|
|
@ -119,7 +119,7 @@ export interface ColumnGroupType<RecordType> extends Omit<ColumnType<RecordType>
|
|||
children: ColumnsType<RecordType>;
|
||||
}
|
||||
|
||||
export type ColumnsType<RecordType = unknown> = (
|
||||
export type ColumnsType<RecordType = DefaultRecordType> = (
|
||||
| ColumnGroupType<RecordType>
|
||||
| ColumnType<RecordType>
|
||||
)[];
|
||||
|
|
|
@ -119,16 +119,19 @@ export default defineComponent<CellProps>({
|
|||
const children = slots.default?.();
|
||||
if (validateValue(children) || cellType === 'header') {
|
||||
childNode = children;
|
||||
if (cellType === 'header' && contextSlots.value.headerCell && !column.slots?.title) {
|
||||
childNode = contextSlots.value.headerCell({ title: column.title, index, column });
|
||||
}
|
||||
} else {
|
||||
const value = getPathValue(record, dataIndex);
|
||||
|
||||
// Customize render node
|
||||
childNode = value;
|
||||
if (customRender) {
|
||||
const renderData = customRender({ text: value, value, record, index, column });
|
||||
const renderData = customRender({
|
||||
text: value,
|
||||
value,
|
||||
record,
|
||||
index,
|
||||
column: column.__originColumn__,
|
||||
});
|
||||
|
||||
if (isRenderCell(renderData)) {
|
||||
childNode = renderData.children;
|
||||
|
@ -139,7 +142,13 @@ export default defineComponent<CellProps>({
|
|||
}
|
||||
|
||||
if (cellType === 'body' && contextSlots.value.bodyCell && !column.slots?.customRender) {
|
||||
childNode = contextSlots.value.bodyCell({ text: value, value, record, index, column });
|
||||
childNode = contextSlots.value.bodyCell({
|
||||
text: value,
|
||||
value,
|
||||
record,
|
||||
index,
|
||||
column: column.__originColumn__,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -67,6 +67,8 @@ interface ColumnSharedType<RecordType> {
|
|||
ellipsis?: CellEllipsisType;
|
||||
align?: AlignType;
|
||||
|
||||
customFilterDropdown?: boolean;
|
||||
|
||||
/** @deprecated Please use `v-slot:filterIcon` `v-slot:bodyCell` `v-slot:headerCell` instead */
|
||||
slots?: {
|
||||
filterIcon?: string;
|
||||
|
@ -74,6 +76,13 @@ interface ColumnSharedType<RecordType> {
|
|||
customRender?: string;
|
||||
title?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* @private Internal usage.
|
||||
*
|
||||
* !!! DO NOT USE IN PRODUCTION ENVIRONMENT !!!
|
||||
*/
|
||||
__originColumn__?: any;
|
||||
}
|
||||
|
||||
export interface ColumnGroupType<RecordType> extends ColumnSharedType<RecordType> {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// debugger tsx
|
||||
import Demo from '../../components/table/demo/ajax.vue';
|
||||
import Demo from '../../components/table/demo/custom-filter-panel.vue';
|
||||
|
||||
export default {
|
||||
render() {
|
||||
|
|
Loading…
Reference in New Issue