diff --git a/packages/devui-vue/devui/table/src/column/use-column.ts b/packages/devui-vue/devui/table/src/column/use-column.ts index 3c63818d2f..df395ba058 100644 --- a/packages/devui-vue/devui/table/src/column/use-column.ts +++ b/packages/devui-vue/devui/table/src/column/use-column.ts @@ -1,12 +1,12 @@ import { watch, reactive, onBeforeMount, ToRefs, Slots, h } from 'vue'; -import { Column, TableColumnPropsTypes } from './column.type' +import { Column, TableColumnPropsTypes } from './column.type'; import { formatWidth, formatMinWidth } from '../utils'; +function defaultRenderHeader(this: Column) { + return h('span', { class: 'title' }, this.header); +} -export function createColumn = any>( - props: ToRefs, - templates: Slots -): Column { +export function createColumn = any>(props: ToRefs, templates: Slots): Column { const { field, header, @@ -20,43 +20,63 @@ export function createColumn = any>( filterMultiple, order, fixedLeft, - fixedRight + fixedRight, } = props; const column: Column = reactive({}); - watch([field, header, order], ([field, header, order]) => { - column.field = field; - column.header = header; - column.order = order; - }, { immediate: true }); + function defaultRenderCell>(rowData: K, index: number) { + const value = rowData[this.field]; + if (templates.default) { + return templates.default(rowData); + } + if (this.formatter) { + return this.formatter(rowData, value, index); + } + + return value?.toString?.() ?? ''; + } + + watch( + [field, header, order], + ([fieldVal, headerVal, orderVal]) => { + column.field = fieldVal; + column.header = headerVal; + column.order = orderVal; + }, + { immediate: true } + ); // 排序功能 - watch([sortable, compareFn], ([sortable, compareFn]) => { - column.sortable = sortable; - column.compareFn = compareFn; - }) + watch([sortable, compareFn], ([sortableVal, compareFnVal]) => { + column.sortable = sortableVal; + column.compareFn = compareFnVal; + }); // 过滤功能 - watch([ - filterable, - filterList, - filterMultiple, - ], ([filterable, filterList, filterMultiple]) => { - column.filterable = filterable; - column.filterMultiple = filterMultiple; - column.filterList = filterList; - }, { immediate: true }) + watch( + [filterable, filterList, filterMultiple], + ([filterableVal, filterListVal, filterMultipleVal]) => { + column.filterable = filterableVal; + column.filterMultiple = filterMultipleVal; + column.filterList = filterListVal; + }, + { immediate: true } + ); // 固定左右功能 - watch([fixedLeft, fixedRight], ([left, right]) => { - column.fixedLeft = left; - column.fixedRight = right; - }, { immediate: true }); + watch( + [fixedLeft, fixedRight], + ([left, right]) => { + column.fixedLeft = left; + column.fixedRight = right; + }, + { immediate: true } + ); // 宽度 - watch([width, minWidth], ([width, minWidth]) => { - column.width = formatWidth(width); - column.minWidth = formatMinWidth(minWidth); + watch([width, minWidth], ([widthVal, minWidthVal]) => { + column.width = formatWidth(widthVal); + column.minWidth = formatMinWidth(minWidthVal); column.realWidth = column.width || column.minWidth; }); @@ -71,15 +91,3 @@ export function createColumn = any>( return column; } - -function defaultRenderHeader(this: Column) { - return h('span', { class: 'title' }, this.header); -} - -function defaultRenderCell>(this: Column, rowData: T, index: number) { - const value = rowData[this.field]; - if (this.formatter) { - return this.formatter(rowData, value, index); - } - return value?.toString?.() ?? ''; -} diff --git a/packages/devui-vue/devui/table/src/fix-header.tsx b/packages/devui-vue/devui/table/src/fix-header.tsx new file mode 100644 index 0000000000..90061c33ed --- /dev/null +++ b/packages/devui-vue/devui/table/src/fix-header.tsx @@ -0,0 +1,36 @@ +import { defineComponent } from 'vue'; +import ColGroup from './colgroup/colgroup'; +import TableHeader from './header/header'; +import TableBody from './body/body'; + +export default defineComponent({ + props: { + classes: { + type: Object, + default: () => ({}), + }, + isEmpty: { + type: Boolean, + }, + }, + setup(props: { classes: Record; isEmpty: boolean }) { + return () => { + return ( +
+
+ + + +
+
+
+ + + {!props.isEmpty && } +
+
+
+ ); + }; + }, +}); diff --git a/packages/devui-vue/devui/table/src/normal-header.tsx b/packages/devui-vue/devui/table/src/normal-header.tsx new file mode 100644 index 0000000000..de1d373376 --- /dev/null +++ b/packages/devui-vue/devui/table/src/normal-header.tsx @@ -0,0 +1,27 @@ +import { defineComponent } from 'vue'; +import ColGroup from './colgroup/colgroup'; +import TableHeader from './header/header'; +import TableBody from './body/body'; + +export default defineComponent({ + props: { + classes: { + type: Object, + default: () => ({}), + }, + isEmpty: { + type: Boolean, + }, + }, + setup(props: { classes: Record; isEmpty: boolean }) { + return () => { + return ( + + + + {!props.isEmpty && } +
+ ); + }; + }, +}); diff --git a/packages/devui-vue/devui/table/src/store/index.ts b/packages/devui-vue/devui/table/src/store/index.ts index 205ff0fac2..9d96d00a86 100644 --- a/packages/devui-vue/devui/table/src/store/index.ts +++ b/packages/devui-vue/devui/table/src/store/index.ts @@ -3,27 +3,31 @@ import { Column, CompareFn, FilterResults } from '../column/column.type'; import { SortDirection } from '../table.type'; export interface TableStore> { states: { - _data: Ref - _columns: Ref - _checkList: Ref - _checkAll: Ref - _halfChecked: Ref - isFixedLeft: Ref - } - insertColumn(column: Column): void - sortColumn(): void - removeColumn(column: Column): void - getCheckedRows(): T[] - sortData(field: string, direction: SortDirection, compareFn: CompareFn): void - filterData(field: string, results: FilterResults): void - resetFilterData(): void + _data: Ref; + _columns: Ref; + _checkList: Ref; + _checkAll: Ref; + _halfChecked: Ref; + isFixedLeft: Ref; + }; + insertColumn(column: Column): void; + sortColumn(): void; + removeColumn(column: Column): void; + getCheckedRows(): T[]; + sortData(field: string, direction: SortDirection, compareFn: CompareFn): void; + filterData(field: string, results: FilterResults): void; + resetFilterData(): void; } export function createStore(dataSource: Ref): TableStore { const _data: Ref = ref([]); - watch(dataSource, (value: T[]) => { - _data.value = [...value]; - }, { deep: true, immediate: true }); + watch( + dataSource, + (value: T[]) => { + _data.value = [...value]; + }, + { deep: true, immediate: true } + ); const { _columns, insertColumn, removeColumn, sortColumn } = createColumnGenerator(); const { _checkAll, _checkList, _halfChecked, getCheckedRows } = createSelection(dataSource, _data); @@ -39,7 +43,7 @@ export function createStore(dataSource: Ref): TableStore { _checkList, _checkAll, _halfChecked, - isFixedLeft + isFixedLeft, }, insertColumn, sortColumn, @@ -47,38 +51,38 @@ export function createStore(dataSource: Ref): TableStore { getCheckedRows, sortData, filterData, - resetFilterData + resetFilterData, }; } /** * 列生成器 - * @returns + * @returns */ const createColumnGenerator = () => { const _columns: Ref = ref([]); /** * 插入当前列 - * @param {Column} column + * @param {Column} column */ const insertColumn = (column: Column) => { _columns.value.push(column); // 实际上就是插入排序 - _columns.value.sort((a, b) => a.order > b.order ? 1 : -1); + _columns.value.sort((a, b) => a.order - b.order); }; /** * 对 column 进行排序 */ const sortColumn = () => { - _columns.value.sort((a, b) => a.order > b.order ? 1 : -1); - } + _columns.value.sort((a, b) => (a.order > b.order ? 1 : -1)); + }; /** * 移除当前列 - * @param {Column} column - * @returns + * @param {Column} column + * @returns */ const removeColumn = (column: Column) => { const i = _columns.value.findIndex((v) => v === column); @@ -86,15 +90,15 @@ const createColumnGenerator = () => { return; } _columns.value.splice(i, 1); - } + }; return { _columns, insertColumn, removeColumn, sortColumn }; -} +}; /** * 选择功能 - * @param dataSource - * @param _data - * @returns + * @param dataSource + * @param _data + * @returns */ const createSelection = (dataSource: Ref, _data: Ref) => { const _checkList: Ref = ref([]); @@ -107,30 +111,37 @@ const createSelection = (dataSource: Ref, _data: Ref) => { for (let i = 0; i < _checkList.value.length; i++) { _checkList.value[i] = val; } - } + }, }); const _halfChecked = ref(false); - watch(dataSource, (value: T[]) => { - _checkList.value = new Array(value.length).fill(false); - }, { deep: true, immediate: true }); + watch( + dataSource, + (value: T[]) => { + _checkList.value = new Array(value.length).fill(false); + }, + { deep: true, immediate: true } + ); // checkList 只有全为true的时候 - watch(_checkList, (list) => { - if (list.length === 0) { - return; - } - let allTrue = true; - let allFalse = true; - for (let i = 0; i < list.length; i++) { - allTrue &&= list[i]; - allFalse &&= !list[i]; - } - - _checkAllRecord.value = allTrue; - _halfChecked.value = !(allFalse || allTrue); + watch( + _checkList, + (list) => { + if (list.length === 0) { + return; + } + let allTrue = true; + let allFalse = true; + for (let i = 0; i < list.length; i++) { + allTrue &&= list[i]; + allFalse &&= !list[i]; + } - }, { immediate: true, deep: true }); + _checkAllRecord.value = allTrue; + _halfChecked.value = !(allFalse || allTrue); + }, + { immediate: true, deep: true } + ); /** * 获取当前已选数据 @@ -138,51 +149,51 @@ const createSelection = (dataSource: Ref, _data: Ref) => { */ const getCheckedRows = (): T[] => { return _data.value.filter((_, index) => _checkList.value[index]); - } + }; return { _checkList, _checkAll, _halfChecked, - getCheckedRows + getCheckedRows, }; -} +}; /** * 排序功能 * @template T - * @param dataSource - * @param _data + * @param dataSource + * @param _data */ const createSorter = (dataSource: Ref, _data: Ref) => { /** * 对数据进行排序 - * @param {string} field - * @param {SortDirection} direction + * @param {string} field + * @param {SortDirection} direction * @param {CompareFn} compareFn */ const sortData = ( field: string, direction: SortDirection, - compareFn: CompareFn = (field: string, a: T, b: T) => a[field] > b[field] + compareFn: CompareFn = (fieldKey: string, a: T, b: T) => a[fieldKey] > b[fieldKey] ) => { if (direction === 'ASC') { - _data.value = _data.value.sort((a, b) => compareFn(field, a, b) ? 1 : -1); + _data.value = _data.value.sort((a, b) => (compareFn(field, a, b) ? 1 : -1)); } else if (direction === 'DESC') { - _data.value = _data.value.sort((a, b) => !compareFn(field, a, b) ? 1 : -1); + _data.value = _data.value.sort((a, b) => (!compareFn(field, a, b) ? 1 : -1)); } else { _data.value = [...dataSource.value]; } - } + }; return { sortData }; -} +}; /** * 过滤功能 * @template T - * @param dataSource - * @param _data - * @returns + * @param dataSource + * @param _data + * @returns */ const createFilter = (dataSource: Ref, _data: Ref) => { // 过滤数据所需要的 @@ -193,26 +204,26 @@ const createFilter = (dataSource: Ref, _data: Ref) => { const filterData = (field: string, results: FilterResults) => { fieldSet.add(field); const fields = [...fieldSet]; - _data.value = dataSource.value.filter(item => { - return fields.reduce((prev, field) => { - return prev && (results.indexOf(item[field]) !== -1) + _data.value = dataSource.value.filter((item) => { + return fields.reduce((prev, fieldKey) => { + return prev && results.indexOf(item[fieldKey]) !== -1; }, true); }); - } + }; /** * 重置数据为最开始的状态 */ const resetFilterData = () => { fieldSet.clear(); _data.value = [...dataSource.value]; - } + }; return { filterData, resetFilterData }; -} +}; const createFixedLogic = (columns: Ref) => { const isFixedLeft = computed(() => { return columns.value.reduce((prev, current) => prev || !!current.fixedLeft, false); }); - return { isFixedLeft } -} + return { isFixedLeft }; +}; diff --git a/packages/devui-vue/devui/table/src/table.tsx b/packages/devui-vue/devui/table/src/table.tsx index 4e52c19a62..bb1b74b7bf 100644 --- a/packages/devui-vue/devui/table/src/table.tsx +++ b/packages/devui-vue/devui/table/src/table.tsx @@ -2,13 +2,10 @@ import { provide, defineComponent, getCurrentInstance, computed, toRef } from 'v import { Table, TableProps, TablePropsTypes, TABLE_TOKEN } from './table.type'; import { useTable } from './use-table'; import { createStore } from './store'; -import ColGroup from './colgroup/colgroup'; -import TableHeader from './header/header'; -import TableBody from './body/body'; - +import FixHeader from './fix-header'; +import NormalHeader from './normal-header'; import './table.scss'; - export default defineComponent({ name: 'DTable', props: TableProps, @@ -17,52 +14,25 @@ export default defineComponent({ const store = createStore(toRef(props, 'data')); table.store = store; provide(TABLE_TOKEN, table); - const { classes, style } = useTable(props); - const isEmpty = computed(() => props.data.length === 0); - const fixHeaderCompo = computed(() => { - return ( -
-
- - - -
-
-
- - - {!isEmpty.value && } -
-
-
- ); - }); - - const normalHeaderCompo = computed(() => { - return ( - - - - {!isEmpty.value && } -
- ) - }); - ctx.expose({ getCheckedRows() { return store.getCheckedRows(); - } + }, }); return () => ( -
+
{ctx.slots.default()} - {props.fixHeader ? fixHeaderCompo.value : normalHeaderCompo.value} - {isEmpty.value &&
No Data
} + {props.fixHeader ? ( + + ) : ( + + )} + {isEmpty.value &&
No Data
}
); - } + }, }); diff --git a/packages/devui-vue/docs/components/table/index.md b/packages/devui-vue/docs/components/table/index.md index 762e2d7622..e09fe58ef0 100644 --- a/packages/devui-vue/docs/components/table/index.md +++ b/packages/devui-vue/docs/components/table/index.md @@ -18,45 +18,52 @@ + + + ``` @@ -68,21 +75,21 @@ ```vue