From 01d2a8182a2766b9b87e6c629fc137b1d55e1bde Mon Sep 17 00:00:00 2001 From: wangyupei <2311595895@qq.com> Date: Sat, 26 Mar 2022 11:53:56 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat(Table):=20=E4=BD=BF=E7=94=A8Rem?= =?UTF-8?q?=E8=A7=84=E8=8C=83=E4=BF=AE=E6=94=B9Table=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devui/table/src/components/body/body.scss | 48 +++++++------- .../devui/table/src/components/body/body.tsx | 11 ++-- .../devui/table/src/components/fix-header.tsx | 15 +++-- .../table/src/components/header/header.scss | 66 ++++++++++--------- .../table/src/components/header/header.tsx | 16 ++--- .../devui/table/src/composable/use-table.ts | 15 +++-- packages/devui-vue/devui/table/src/table.scss | 42 ++++++------ packages/devui-vue/devui/table/src/table.tsx | 6 +- .../devui-vue/docs/components/table/index.md | 2 +- 9 files changed, 117 insertions(+), 104 deletions(-) diff --git a/packages/devui-vue/devui/table/src/components/body/body.scss b/packages/devui-vue/devui/table/src/components/body/body.scss index 22adac91ad..b11c2bb875 100644 --- a/packages/devui-vue/devui/table/src/components/body/body.scss +++ b/packages/devui-vue/devui/table/src/components/body/body.scss @@ -1,34 +1,38 @@ @import '../../../../styles-var/devui-var.scss'; -.devui-tbody { - tr { - font-size: $devui-font-size-card-title; - color: $devui-text; - border: none; - border-bottom: 1px solid $devui-dividing-line; - background-color: $devui-base-bg; +.devui-table { + &__tbody { + tr { + font-size: $devui-font-size-card-title; + color: $devui-text; + border: none; + border-bottom: 1px solid $devui-dividing-line; + background-color: $devui-base-bg; - &.hover-enabled:hover { - background-color: $devui-list-item-hover-bg; - } + &.hover-enabled:hover { + background-color: $devui-list-item-hover-bg; + } - td { - padding: 10px; - border: none; + td { + padding: 10px; + border: none; + } } } } -.devui-sticky-cell { - position: sticky; - z-index: 5; - background-color: inherit; +.devui-table { + &--sticky-cell { + position: sticky; + z-index: 5; + background-color: inherit; - &.left { - box-shadow: rgba(0, 0, 0, 0.05) $devui-shadow-length-slide-right; - } + &.left { + box-shadow: rgba(0, 0, 0, 0.05) $devui-shadow-length-slide-right; + } - &.right { - box-shadow: rgba(0, 0, 0, 0.05) $devui-shadow-length-slide-left; + &.right { + box-shadow: rgba(0, 0, 0, 0.05) $devui-shadow-length-slide-left; + } } } diff --git a/packages/devui-vue/devui/table/src/components/body/body.tsx b/packages/devui-vue/devui/table/src/components/body/body.tsx index af6349e5a8..3780f6e548 100644 --- a/packages/devui-vue/devui/table/src/components/body/body.tsx +++ b/packages/devui-vue/devui/table/src/components/body/body.tsx @@ -1,16 +1,17 @@ import { defineComponent, inject, computed, PropType, toRef } from 'vue'; import { TABLE_TOKEN } from '../../table-types'; -import { Checkbox } from '../../../../checkbox'; - -import './body.scss'; import { Column } from '../column/column-types'; +import { Checkbox } from '../../../../checkbox'; import { useFixedColumn } from '../../composable/use-table'; +import { useNamespace } from '../../../../shared/hooks/use-namespace'; +import './body.scss'; export default defineComponent({ name: 'DTableBody', setup() { const table = inject(TABLE_TOKEN); const { _data: data, _columns: columns, _checkList: checkList, isFixedLeft } = table.store.states; + const ns = useNamespace('table'); // 移动到行上是否高亮 const hoverEnabled = computed(() => table.props.rowHoveredHighlight); @@ -19,7 +20,7 @@ export default defineComponent({ const tdAttrs = computed(() => isFixedLeft.value ? { - class: 'devui-sticky-cell left', + class: `${ns.m('sticky-cell')} left`, style: 'left:0;', } : null @@ -32,7 +33,7 @@ export default defineComponent({ ) : null; return () => ( - + {data.value.map((row, rowIndex) => { return ( diff --git a/packages/devui-vue/devui/table/src/components/fix-header.tsx b/packages/devui-vue/devui/table/src/components/fix-header.tsx index 90061c33ed..cb5a527e5b 100644 --- a/packages/devui-vue/devui/table/src/components/fix-header.tsx +++ b/packages/devui-vue/devui/table/src/components/fix-header.tsx @@ -2,6 +2,7 @@ import { defineComponent } from 'vue'; import ColGroup from './colgroup/colgroup'; import TableHeader from './header/header'; import TableBody from './body/body'; +import { useNamespace } from '../../../shared/hooks/use-namespace'; export default defineComponent({ props: { @@ -14,19 +15,21 @@ export default defineComponent({ }, }, setup(props: { classes: Record; isEmpty: boolean }) { + const ns = useNamespace('table'); + return () => { return ( -
-
- +
+
+
-
- +
+
- {!props.isEmpty && } + {!props.isEmpty && }
diff --git a/packages/devui-vue/devui/table/src/components/header/header.scss b/packages/devui-vue/devui/table/src/components/header/header.scss index e7b9fddb44..21354df112 100644 --- a/packages/devui-vue/devui/table/src/components/header/header.scss +++ b/packages/devui-vue/devui/table/src/components/header/header.scss @@ -1,44 +1,48 @@ @import '../../../../styles-var/devui-var.scss'; -.devui-thead { - tr { - font-size: $devui-font-size-card-title; - color: $devui-text; - font-weight: 700; - border: none; - border-bottom: 1px solid $devui-line; - background-color: $devui-base-bg; - - th { - text-align: left; - padding: 0; +.devui-table { + &__thead { + tr { + font-size: $devui-font-size-card-title; + color: $devui-text; + font-weight: 700; border: none; + border-bottom: 1px solid $devui-line; + background-color: $devui-base-bg; + + th { + text-align: left; + padding: 0; + border: none; + } } - } - .header-container { - position: relative; - display: flex; - align-items: center; - padding-left: 2px; - padding-right: 8px; + .header-container { + position: relative; + display: flex; + align-items: center; + padding-left: 2px; + padding-right: 8px; - .title { - display: inline-block; - line-height: 36px; - vertical-align: middle; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - cursor: default; + .title { + display: inline-block; + line-height: 36px; + vertical-align: middle; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + cursor: default; + } } } } -.header-bg { - thead.devui-thead { - tr { - background: var(--devui-list-item-hover-bg, #f2f5fc); +.devui-table { + &--header-bg { + thead.devui-thead { + tr { + background: var(--devui-list-item-hover-bg, #f2f5fc); + } } } } diff --git a/packages/devui-vue/devui/table/src/components/header/header.tsx b/packages/devui-vue/devui/table/src/components/header/header.tsx index 01d56859c0..a5b0d7ba29 100644 --- a/packages/devui-vue/devui/table/src/components/header/header.tsx +++ b/packages/devui-vue/devui/table/src/components/header/header.tsx @@ -1,26 +1,26 @@ import { defineComponent, inject, computed, PropType, toRefs } from 'vue'; import { TABLE_TOKEN } from '../../table-types'; import { Column } from '../column/column-types'; - import { Checkbox } from '../../../../checkbox'; import { Sort } from '../sort'; import { Filter } from '../filter'; - -import './header.scss'; -import '../body/body.scss'; import { useFliter, useSort } from './use-header'; import { useFixedColumn } from '../../composable/use-table'; +import { useNamespace } from '../../../../shared/hooks/use-namespace'; +import './header.scss'; +import '../body/body.scss'; export default defineComponent({ name: 'DTableHeader', setup() { const table = inject(TABLE_TOKEN); const { _checkAll: checkAll, _halfChecked: halfChecked, _columns: columns, isFixedLeft } = table.store.states; + const ns = useNamespace('table'); const thAttrs = computed(() => isFixedLeft.value ? { - class: 'devui-sticky-cell left', + class: `${ns.m('sticky-cell')} left`, style: 'left:0;', } : null @@ -28,14 +28,14 @@ export default defineComponent({ const checkbox = computed(() => table.props.checkable ? ( - + ) : null ); return () => { return ( - + {checkbox.value} {columns.value.map((column, index) => ( @@ -70,7 +70,7 @@ const Th = defineComponent({ return () => ( -
+
{props.column.renderHeader()} {props.column.filterable && ( diff --git a/packages/devui-vue/devui/table/src/composable/use-table.ts b/packages/devui-vue/devui/table/src/composable/use-table.ts index 43fdfdaaed..c9b172a4b4 100644 --- a/packages/devui-vue/devui/table/src/composable/use-table.ts +++ b/packages/devui-vue/devui/table/src/composable/use-table.ts @@ -1,6 +1,7 @@ import { computed, ComputedRef, CSSProperties, Ref, ToRefs } from 'vue'; import { Column } from '../components/column/column-types'; import { TablePropsTypes } from '../table-types'; +import { useNamespace } from '../../../shared/hooks/use-namespace'; interface TableConfig { classes: ComputedRef>; @@ -8,11 +9,12 @@ interface TableConfig { } export function useTable(props: TablePropsTypes): TableConfig { + const ns = useNamespace('table'); const classes = computed(() => ({ - 'devui-table': true, - 'devui-table-striped': props.striped, - 'header-bg': props.headerBg, - 'table-layout-auto': props.tableLayout === 'auto', + [ns.e('view')]: true, + [ns.m('striped')]: props.striped, + [ns.m('header-bg')]: props.headerBg, + [ns.m('layout-auto')]: props.tableLayout === 'auto', })); const style: ComputedRef = computed(() => ({ maxHeight: props.maxHeight, @@ -24,14 +26,15 @@ export function useTable(props: TablePropsTypes): TableConfig { } export const useFixedColumn = (column: Ref): ToRefs<{ stickyCell: string; offsetStyle: string }> => { + const ns = useNamespace('table'); const stickyCell = computed(() => { const col = column.value; if (col.fixedLeft) { - return `devui-sticky-cell left`; + return `${ns.m('sticky-cell')} left`; } if (col.fixedRight) { - return `devui-sticky-cell right`; + return `${ns.m('sticky-cell')} right`; } return undefined; }); diff --git a/packages/devui-vue/devui/table/src/table.scss b/packages/devui-vue/devui/table/src/table.scss index 125f13cc1f..c0f24c0953 100644 --- a/packages/devui-vue/devui/table/src/table.scss +++ b/packages/devui-vue/devui/table/src/table.scss @@ -1,49 +1,45 @@ @import '../../styles-var/devui-var.scss'; .devui-table { - display: table; - table-layout: fixed; width: 100%; - border-spacing: 0; - border: none; - margin: 0; - padding: 0; + overflow-x: auto; + padding-top: 8px; - &-wrapper { + &__view { + display: table; + table-layout: fixed; width: 100%; - overflow-x: auto; - padding-top: 8px; + border-spacing: 0; + border: none; + margin: 0; + padding: 0; } - &-striped { + &--striped { tbody tr:nth-child(even) { background-color: $devui-list-item-strip-bg; } } - &-empty { + &__empty { width: 100%; font-size: $devui-font-size; text-align: center; } - &-view { + &__fix-header { display: flex; flex-direction: column; position: relative; height: 100%; - - & .scroll-view { - flex: 1; - overflow: scroll; - } } -} -.table-layout-auto { - table-layout: auto; -} + &__scroll-view { + flex: 1; + overflow: scroll; + } -.table-layout-auto { - table-layout: auto; + &--layout-auto { + table-layout: auto; + } } diff --git a/packages/devui-vue/devui/table/src/table.tsx b/packages/devui-vue/devui/table/src/table.tsx index bb091d4fdc..31caddb16e 100644 --- a/packages/devui-vue/devui/table/src/table.tsx +++ b/packages/devui-vue/devui/table/src/table.tsx @@ -5,6 +5,7 @@ import { createStore } from './store'; import FixHeader from './components/fix-header'; import NormalHeader from './components/normal-header'; import { Loading } from '../../loading'; +import { useNamespace } from '../../shared/hooks/use-namespace'; import './table.scss'; export default defineComponent({ @@ -20,6 +21,7 @@ export default defineComponent({ provide(TABLE_TOKEN, table); const { classes, style } = useTable(props); const isEmpty = computed(() => props.data.length === 0); + const ns = useNamespace('table'); ctx.expose({ getCheckedRows() { @@ -28,14 +30,14 @@ export default defineComponent({ }); return () => ( -
+
{ctx.slots.default?.()} {props.fixHeader ? ( ) : ( )} - {isEmpty.value &&
No Data
} + {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 73e23e56e6..4087da3215 100644 --- a/packages/devui-vue/docs/components/table/index.md +++ b/packages/devui-vue/docs/components/table/index.md @@ -226,7 +226,7 @@ export default defineComponent({
更新数据 - + From 4faa703b66fa9a9bb1b8aa0edde046b508b62951 Mon Sep 17 00:00:00 2001 From: wangyupei <2311595895@qq.com> Date: Sat, 26 Mar 2022 14:54:34 +0800 Subject: [PATCH 2/5] =?UTF-8?q?refactor(Table):=20TD=E5=92=8CTH=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E4=BB=8Ebody=E3=80=81header=E4=B8=AD=E6=8A=BD?= =?UTF-8?q?=E7=A6=BB,=E8=A7=A3=E5=86=B3=E4=B8=80=E4=B8=AA=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=AE=9A=E4=B9=89=E5=A4=9A=E4=B8=AA=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E7=9A=84eslint=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../table/src/components/body-td/body-td.tsx | 34 ++++++++++++ .../devui/table/src/components/body/body.tsx | 43 ++------------- .../src/components/header-th/header-th.tsx | 37 +++++++++++++ .../use-header-th.ts} | 2 +- .../table/src/components/header/header.tsx | 53 ++----------------- .../components/PageContributorConfig.ts | 4 ++ 6 files changed, 83 insertions(+), 90 deletions(-) create mode 100644 packages/devui-vue/devui/table/src/components/body-td/body-td.tsx create mode 100644 packages/devui-vue/devui/table/src/components/header-th/header-th.tsx rename packages/devui-vue/devui/table/src/components/{header/use-header.ts => header-th/use-header-th.ts} (92%) diff --git a/packages/devui-vue/devui/table/src/components/body-td/body-td.tsx b/packages/devui-vue/devui/table/src/components/body-td/body-td.tsx new file mode 100644 index 0000000000..9b76b8c8bf --- /dev/null +++ b/packages/devui-vue/devui/table/src/components/body-td/body-td.tsx @@ -0,0 +1,34 @@ +import { defineComponent, toRef } from 'vue'; +import type { PropType } from 'vue'; +import { Column } from '../column/column-types'; +import { useFixedColumn } from '../../composable/use-table'; + +export default defineComponent({ + name: 'DTableBodyTd', + props: { + column: { + type: Object as PropType, + default: () => ({}), + }, + row: { + type: Object, + default: () => ({}), + }, + index: { + type: Number, + default: 0, + }, + }, + setup(props: { column: Column; row: any; index: number }) { + const column = toRef(props, 'column'); + + // 固定列 + const { stickyCell, offsetStyle } = useFixedColumn(column); + + return () => ( + + {column.value.renderCell?.(props.row, props.index)} + + ); + }, +}); diff --git a/packages/devui-vue/devui/table/src/components/body/body.tsx b/packages/devui-vue/devui/table/src/components/body/body.tsx index 3780f6e548..eb848ddee9 100644 --- a/packages/devui-vue/devui/table/src/components/body/body.tsx +++ b/packages/devui-vue/devui/table/src/components/body/body.tsx @@ -1,8 +1,7 @@ -import { defineComponent, inject, computed, PropType, toRef } from 'vue'; +import { defineComponent, inject, computed } from 'vue'; import { TABLE_TOKEN } from '../../table-types'; -import { Column } from '../column/column-types'; +import TD from '../body-td/body-td'; import { Checkbox } from '../../../../checkbox'; -import { useFixedColumn } from '../../composable/use-table'; import { useNamespace } from '../../../../shared/hooks/use-namespace'; import './body.scss'; @@ -12,19 +11,9 @@ export default defineComponent({ const table = inject(TABLE_TOKEN); const { _data: data, _columns: columns, _checkList: checkList, isFixedLeft } = table.store.states; const ns = useNamespace('table'); - - // 移动到行上是否高亮 const hoverEnabled = computed(() => table.props.rowHoveredHighlight); - // 行前的 checkbox - const tdAttrs = computed(() => - isFixedLeft.value - ? { - class: `${ns.m('sticky-cell')} left`, - style: 'left:0;', - } - : null - ); + const tdAttrs = computed(() => (isFixedLeft.value ? { class: `${ns.m('sticky-cell')} left`, style: 'left:0;' } : null)); const renderCheckbox = (index: number) => table.props.checkable ? ( @@ -48,29 +37,3 @@ export default defineComponent({ ); }, }); - -const TD = defineComponent({ - props: { - column: { - type: Object as PropType, - }, - row: { - type: Object, - }, - index: { - type: Number, - }, - }, - setup(props: { column: Column; row: any; index: number }) { - const column = toRef(props, 'column'); - - // 固定列 - const { stickyCell, offsetStyle } = useFixedColumn(column); - - return () => ( - - {column.value.renderCell(props.row, props.index)} - - ); - }, -}); diff --git a/packages/devui-vue/devui/table/src/components/header-th/header-th.tsx b/packages/devui-vue/devui/table/src/components/header-th/header-th.tsx new file mode 100644 index 0000000000..236b686a3c --- /dev/null +++ b/packages/devui-vue/devui/table/src/components/header-th/header-th.tsx @@ -0,0 +1,37 @@ +import { defineComponent, inject, toRefs } from 'vue'; +import { PropType } from 'vue'; +import { Column } from '../column/column-types'; +import { TABLE_TOKEN } from '../../table-types'; +import { Sort } from '../sort'; +import { Filter } from '../filter'; +import { useFixedColumn } from '../../composable/use-table'; +import { useSort, useFilter } from './use-header-th'; + +export default defineComponent({ + name: 'DTableHeaderTh', + props: { + column: { + type: Object as PropType, + required: true, + }, + }, + setup(props: { column: Column }) { + const table = inject(TABLE_TOKEN); + const { column } = toRefs(props); + const directionRef = useSort(table.store, column); + const filteredRef = useFilter(table.store, column); + const { stickyCell, offsetStyle } = useFixedColumn(column); + + return () => ( + +
+ {props.column.renderHeader?.()} + {props.column.filterable && ( + + )} +
+ {props.column.sortable && } + + ); + }, +}); diff --git a/packages/devui-vue/devui/table/src/components/header/use-header.ts b/packages/devui-vue/devui/table/src/components/header-th/use-header-th.ts similarity index 92% rename from packages/devui-vue/devui/table/src/components/header/use-header.ts rename to packages/devui-vue/devui/table/src/components/header-th/use-header-th.ts index f9145ec5b0..151aaf246f 100644 --- a/packages/devui-vue/devui/table/src/components/header/use-header.ts +++ b/packages/devui-vue/devui/table/src/components/header-th/use-header-th.ts @@ -19,7 +19,7 @@ export const useSort = (store: TableStore, column: Ref): Ref): Ref => { +export const useFilter = (store: TableStore, column: Ref): Ref => { const filteredRef = shallowRef(); watch(filteredRef, (results) => { store.filterData(column.value.field, results); diff --git a/packages/devui-vue/devui/table/src/components/header/header.tsx b/packages/devui-vue/devui/table/src/components/header/header.tsx index a5b0d7ba29..4bcfeaa7b1 100644 --- a/packages/devui-vue/devui/table/src/components/header/header.tsx +++ b/packages/devui-vue/devui/table/src/components/header/header.tsx @@ -1,11 +1,7 @@ -import { defineComponent, inject, computed, PropType, toRefs } from 'vue'; +import { defineComponent, inject, computed } from 'vue'; import { TABLE_TOKEN } from '../../table-types'; -import { Column } from '../column/column-types'; import { Checkbox } from '../../../../checkbox'; -import { Sort } from '../sort'; -import { Filter } from '../filter'; -import { useFliter, useSort } from './use-header'; -import { useFixedColumn } from '../../composable/use-table'; +import TH from '../header-th/header-th'; import { useNamespace } from '../../../../shared/hooks/use-namespace'; import './header.scss'; import '../body/body.scss'; @@ -17,14 +13,7 @@ export default defineComponent({ const { _checkAll: checkAll, _halfChecked: halfChecked, _columns: columns, isFixedLeft } = table.store.states; const ns = useNamespace('table'); - const thAttrs = computed(() => - isFixedLeft.value - ? { - class: `${ns.m('sticky-cell')} left`, - style: 'left:0;', - } - : null - ); + const thAttrs = computed(() => (isFixedLeft.value ? { class: `${ns.m('sticky-cell')} left`, style: 'left:0;' } : null)); const checkbox = computed(() => table.props.checkable ? ( @@ -39,7 +28,7 @@ export default defineComponent({ {checkbox.value} {columns.value.map((column, index) => ( - + ))} @@ -47,37 +36,3 @@ export default defineComponent({ }; }, }); - -const Th = defineComponent({ - props: { - column: { - type: Object as PropType, - required: true, - }, - }, - setup(props: { column: Column }) { - const table = inject(TABLE_TOKEN); - const { column } = toRefs(props); - - // 排序功能 - const directionRef = useSort(table.store, column); - - // 过滤器 - const filteredRef = useFliter(table.store, column); - - // 固定列功能 - const { stickyCell, offsetStyle } = useFixedColumn(column); - - return () => ( - -
- {props.column.renderHeader()} - {props.column.filterable && ( - - )} -
- {props.column.sortable && } - - ); - }, -}); diff --git a/packages/devui-vue/docs/.vitepress/devui-theme/components/PageContributorConfig.ts b/packages/devui-vue/docs/.vitepress/devui-theme/components/PageContributorConfig.ts index 841e8d7eea..a80942e80b 100644 --- a/packages/devui-vue/docs/.vitepress/devui-theme/components/PageContributorConfig.ts +++ b/packages/devui-vue/docs/.vitepress/devui-theme/components/PageContributorConfig.ts @@ -486,6 +486,10 @@ export const CONTRIBUTORS_MAP: IContributingMap = { avatar: 'https://portrait.gitee.com/uploads/avatars/user/757/2273663_weban_1611113629.png!avatar200', homepage: 'https://gitee.com/weban' }, + { + avatar: 'https://avatars.githubusercontent.com/u/11143986?v=4', + homepage: 'https://github.com/xingyan95' + }, ], tag: [ { From ff7362ad31e45de21fb1df16f24a409f2e82f1b4 Mon Sep 17 00:00:00 2001 From: wangyupei <2311595895@qq.com> Date: Sat, 26 Mar 2022 17:52:23 +0800 Subject: [PATCH 3/5] =?UTF-8?q?feat(Table):=20=E5=AE=8C=E6=88=90Table?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E5=90=88=E5=B9=B6=E5=8D=95=E5=85=83=E6=A0=BC?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devui/table/src/components/body/body.tsx | 16 +++- .../table/src/components/body/use-body.ts | 67 ++++++++++++++-- .../devui-vue/devui/table/src/table-types.ts | 10 +++ .../devui-vue/docs/components/table/index.md | 79 +++++++++++++++++++ 4 files changed, 163 insertions(+), 9 deletions(-) diff --git a/packages/devui-vue/devui/table/src/components/body/body.tsx b/packages/devui-vue/devui/table/src/components/body/body.tsx index eb848ddee9..d86dd9b3cc 100644 --- a/packages/devui-vue/devui/table/src/components/body/body.tsx +++ b/packages/devui-vue/devui/table/src/components/body/body.tsx @@ -3,6 +3,7 @@ import { TABLE_TOKEN } from '../../table-types'; import TD from '../body-td/body-td'; import { Checkbox } from '../../../../checkbox'; import { useNamespace } from '../../../../shared/hooks/use-namespace'; +import { useBody } from './use-body'; import './body.scss'; export default defineComponent({ @@ -12,8 +13,9 @@ export default defineComponent({ const { _data: data, _columns: columns, _checkList: checkList, isFixedLeft } = table.store.states; const ns = useNamespace('table'); const hoverEnabled = computed(() => table.props.rowHoveredHighlight); - + const { tableSpans, removeCells } = useBody(); const tdAttrs = computed(() => (isFixedLeft.value ? { class: `${ns.m('sticky-cell')} left`, style: 'left:0;' } : null)); + const renderCheckbox = (index: number) => table.props.checkable ? ( @@ -27,9 +29,15 @@ export default defineComponent({ return ( {renderCheckbox(rowIndex)} - {columns.value.map((column, index) => ( - - ))} + {columns.value.map((column, columnIndex) => { + const cellId = `${rowIndex}-${columnIndex}`; + const [rowspan, colspan] = tableSpans.value[cellId] ?? [1, 1]; + + if (removeCells.value.includes(cellId)) { + return null; + } + return ; + })} ); })} diff --git a/packages/devui-vue/devui/table/src/components/body/use-body.ts b/packages/devui-vue/devui/table/src/components/body/use-body.ts index 7a66b98a06..8abef2d5cb 100644 --- a/packages/devui-vue/devui/table/src/components/body/use-body.ts +++ b/packages/devui-vue/devui/table/src/components/body/use-body.ts @@ -1,7 +1,64 @@ -import { computed, ComputedRef } from 'vue'; -import { Column } from '../column/column-types'; -import { TableBodyPropsTypes } from './body-types'; +import { inject, computed } from 'vue'; +import { TABLE_TOKEN } from '../../table-types'; -interface Data { - rowColumns: ComputedRef<(Record & { columns: Column[] })[]>; +export function useBody() { + const table = inject(TABLE_TOKEN); + const { _data: data, _columns: columns } = table.store.states; + + const getSpan = (row: any, column: any, rowIndex: number, columnIndex: number) => { + const fn = table?.props.spanMethod; + let rowspan = 1; + let colspan = 1; + + if (typeof fn === 'function') { + const result = fn({ row, column, rowIndex, columnIndex }); + + if (Array.isArray(result)) { + rowspan = result[0]; + colspan = result[1]; + } else if (typeof result === 'object') { + rowspan = result.rowspan; + colspan = result.colspan; + } + } + + return { rowspan, colspan }; + }; + + const tableSpans = computed(() => { + const result: Record = {}; + + if (table?.props.spanMethod) { + data.value.forEach((row, rowIndex) => { + columns.value.forEach((column, columnIndex) => { + const { rowspan, colspan } = getSpan(row, column, rowIndex, columnIndex); + if (rowspan > 1 || colspan > 1) { + result[`${rowIndex}-${columnIndex}`] = [rowspan, colspan]; + } + }); + }); + } + + return result; + }); + + const removeCells = computed(() => { + const result: string[] = []; + for (const indexKey of Object.keys(tableSpans.value)) { + const indexArray = indexKey.split('-').map((item) => Number(item)); + const spans = tableSpans.value[indexKey]; + for (let i = 1; i < spans[0]; i++) { + result.push(`${indexArray[0] + i}-${indexArray[1]}`); + for (let j = 1; j < spans[1]; j++) { + result.push(`${indexArray[0] + i}-${indexArray[1] + j}`); + } + } + for (let i = 1; i < spans[1]; i++) { + result.push(`${indexArray[0]}-${indexArray[1] + i}`); + } + } + return result; + }); + + return { tableSpans, removeCells }; } diff --git a/packages/devui-vue/devui/table/src/table-types.ts b/packages/devui-vue/devui/table/src/table-types.ts index c17bb0ae35..837d574bc2 100644 --- a/packages/devui-vue/devui/table/src/table-types.ts +++ b/packages/devui-vue/devui/table/src/table-types.ts @@ -3,6 +3,13 @@ import { TableStore } from './store'; export type TableSize = 'sm' | 'md' | 'lg'; +export type SpanMethod = (data: { + row: any; + column: any; + rowIndex: number; + columnIndex: number; +}) => number[] | { rowspan: number; colspan: number }; + export const TableProps = { data: { type: Array as PropType[]>, @@ -61,6 +68,9 @@ export const TableProps = { type: Boolean, default: false, }, + spanMethod: { + type: Function as PropType, + }, }; export type TablePropsTypes = ExtractPropTypes; diff --git a/packages/devui-vue/docs/components/table/index.md b/packages/devui-vue/docs/components/table/index.md index 4087da3215..e26208b735 100644 --- a/packages/devui-vue/docs/components/table/index.md +++ b/packages/devui-vue/docs/components/table/index.md @@ -302,6 +302,71 @@ export default defineComponent({ ::: +### 合并单元格 + +:::demo 通过`span-method`方法可以自定义合并单元格,方法参数是一个对象,对象包含属性如下:当前行`row`、当前列`column`、当前行索引`rowIndex`、当前列索引`columnIndex`。该方法可以返回包含两个元素的数组,第一个元素是`rowspan`,第二个元素是`colspan`;也可以返回一个对象,属性为`rowspan`和`colspan`。 + +```vue + + + +``` + +::: + ### d-table 参数 | 参数 | 类型 | 默认值 | 说明 | @@ -318,6 +383,7 @@ export default defineComponent({ | show-loading | `Boolean` | false | 显示加载动画 | | header-bg | `Boolean` | false | 头部背景 | | table-layout | `'fixed' \| 'auto'` | 'fixed' | 表格布局,可选值为'auto' | +| span-method | `SpanMethod` | -- | 合并单元格的计算方法 | ### d-column 参数 @@ -336,3 +402,16 @@ export default defineComponent({ | 名称 | 说明 | | :------ | :--------------------- | | default | 默认插槽,自定义列内容 | + +### 类型定义 + +#### SpanMethod + +```typescript +type SpanMethod = (data: { + row: any; + column: any; + rowIndex: number; + columnIndex: number; +}) => number[] | { rowspan: number; colspan: number }; +``` From fc893ee9d9458cadf82839e475d9ad1b9b9a8808 Mon Sep 17 00:00:00 2001 From: wangyupei <2311595895@qq.com> Date: Mon, 28 Mar 2022 14:08:27 +0800 Subject: [PATCH 4/5] =?UTF-8?q?feat(Table):=20=E4=BF=AE=E6=94=B9=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/devui-vue/devui/table/src/components/body/body.tsx | 4 ++-- .../devui-vue/devui/table/src/components/body/use-body.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/devui-vue/devui/table/src/components/body/body.tsx b/packages/devui-vue/devui/table/src/components/body/body.tsx index d86dd9b3cc..412b6c2711 100644 --- a/packages/devui-vue/devui/table/src/components/body/body.tsx +++ b/packages/devui-vue/devui/table/src/components/body/body.tsx @@ -3,7 +3,7 @@ import { TABLE_TOKEN } from '../../table-types'; import TD from '../body-td/body-td'; import { Checkbox } from '../../../../checkbox'; import { useNamespace } from '../../../../shared/hooks/use-namespace'; -import { useBody } from './use-body'; +import { useMergeCell } from './use-body'; import './body.scss'; export default defineComponent({ @@ -13,7 +13,7 @@ export default defineComponent({ const { _data: data, _columns: columns, _checkList: checkList, isFixedLeft } = table.store.states; const ns = useNamespace('table'); const hoverEnabled = computed(() => table.props.rowHoveredHighlight); - const { tableSpans, removeCells } = useBody(); + const { tableSpans, removeCells } = useMergeCell(); const tdAttrs = computed(() => (isFixedLeft.value ? { class: `${ns.m('sticky-cell')} left`, style: 'left:0;' } : null)); const renderCheckbox = (index: number) => diff --git a/packages/devui-vue/devui/table/src/components/body/use-body.ts b/packages/devui-vue/devui/table/src/components/body/use-body.ts index 8abef2d5cb..f7a998b707 100644 --- a/packages/devui-vue/devui/table/src/components/body/use-body.ts +++ b/packages/devui-vue/devui/table/src/components/body/use-body.ts @@ -1,7 +1,7 @@ import { inject, computed } from 'vue'; import { TABLE_TOKEN } from '../../table-types'; -export function useBody() { +export function useMergeCell() { const table = inject(TABLE_TOKEN); const { _data: data, _columns: columns } = table.store.states; From 0e3a372113f1ca367db3e159063b9771612e2f6d Mon Sep 17 00:00:00 2001 From: wangyupei <2311595895@qq.com> Date: Mon, 28 Mar 2022 17:09:40 +0800 Subject: [PATCH 5/5] =?UTF-8?q?feat(Table):=20=E8=A1=A8=E6=A0=BC=E6=94=AF?= =?UTF-8?q?=E6=8C=81sm/md/lg=E4=B8=89=E7=A7=8D=E5=A4=A7=E5=B0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devui/table/src/components/body/body.scss | 11 ++-- .../devui/table/src/components/body/body.tsx | 2 +- .../table/src/components/header/header.scss | 4 +- .../table/src/components/header/header.tsx | 4 +- .../devui/table/src/composable/use-table.ts | 1 + .../devui-vue/devui/table/src/table-types.ts | 3 +- packages/devui-vue/devui/table/src/table.scss | 35 ++++++++++ .../devui-vue/docs/components/table/index.md | 64 +++++++++++++------ 8 files changed, 94 insertions(+), 30 deletions(-) diff --git a/packages/devui-vue/devui/table/src/components/body/body.scss b/packages/devui-vue/devui/table/src/components/body/body.scss index b11c2bb875..ac6acb04fb 100644 --- a/packages/devui-vue/devui/table/src/components/body/body.scss +++ b/packages/devui-vue/devui/table/src/components/body/body.scss @@ -3,10 +3,8 @@ .devui-table { &__tbody { tr { - font-size: $devui-font-size-card-title; + font-size: $devui-font-size; color: $devui-text; - border: none; - border-bottom: 1px solid $devui-dividing-line; background-color: $devui-base-bg; &.hover-enabled:hover { @@ -14,8 +12,13 @@ } td { - padding: 10px; + background-clip: padding-box; + vertical-align: middle; + word-wrap: break-word; + word-break: normal; + line-height: 24px; border: none; + border-bottom: 1px solid $devui-dividing-line; } } } diff --git a/packages/devui-vue/devui/table/src/components/body/body.tsx b/packages/devui-vue/devui/table/src/components/body/body.tsx index 412b6c2711..46460c58d2 100644 --- a/packages/devui-vue/devui/table/src/components/body/body.tsx +++ b/packages/devui-vue/devui/table/src/components/body/body.tsx @@ -18,7 +18,7 @@ export default defineComponent({ const renderCheckbox = (index: number) => table.props.checkable ? ( - + ) : null; diff --git a/packages/devui-vue/devui/table/src/components/header/header.scss b/packages/devui-vue/devui/table/src/components/header/header.scss index 21354df112..cbd490115e 100644 --- a/packages/devui-vue/devui/table/src/components/header/header.scss +++ b/packages/devui-vue/devui/table/src/components/header/header.scss @@ -6,14 +6,12 @@ font-size: $devui-font-size-card-title; color: $devui-text; font-weight: 700; - border: none; - border-bottom: 1px solid $devui-line; background-color: $devui-base-bg; th { text-align: left; - padding: 0; border: none; + border-bottom: 1px solid $devui-line; } } diff --git a/packages/devui-vue/devui/table/src/components/header/header.tsx b/packages/devui-vue/devui/table/src/components/header/header.tsx index 4bcfeaa7b1..f544c240ca 100644 --- a/packages/devui-vue/devui/table/src/components/header/header.tsx +++ b/packages/devui-vue/devui/table/src/components/header/header.tsx @@ -16,8 +16,8 @@ export default defineComponent({ const thAttrs = computed(() => (isFixedLeft.value ? { class: `${ns.m('sticky-cell')} left`, style: 'left:0;' } : null)); const checkbox = computed(() => table.props.checkable ? ( - - + + ) : null ); diff --git a/packages/devui-vue/devui/table/src/composable/use-table.ts b/packages/devui-vue/devui/table/src/composable/use-table.ts index c9b172a4b4..ac818eebf4 100644 --- a/packages/devui-vue/devui/table/src/composable/use-table.ts +++ b/packages/devui-vue/devui/table/src/composable/use-table.ts @@ -15,6 +15,7 @@ export function useTable(props: TablePropsTypes): TableConfig { [ns.m('striped')]: props.striped, [ns.m('header-bg')]: props.headerBg, [ns.m('layout-auto')]: props.tableLayout === 'auto', + [ns.m(`${props.size}`)]: true, })); const style: ComputedRef = computed(() => ({ maxHeight: props.maxHeight, diff --git a/packages/devui-vue/devui/table/src/table-types.ts b/packages/devui-vue/devui/table/src/table-types.ts index 837d574bc2..cae7f97b81 100644 --- a/packages/devui-vue/devui/table/src/table-types.ts +++ b/packages/devui-vue/devui/table/src/table-types.ts @@ -40,6 +40,7 @@ export const TableProps = { validator(value: string): boolean { return value === 'sm' || value === 'md' || value === 'lg'; }, + default: 'sm', }, rowHoveredHighlight: { type: Boolean, @@ -51,7 +52,7 @@ export const TableProps = { }, checkable: { type: Boolean, - default: true, + default: false, }, tableLayout: { type: String as PropType<'fixed' | 'auto'>, diff --git a/packages/devui-vue/devui/table/src/table.scss b/packages/devui-vue/devui/table/src/table.scss index c0f24c0953..185bd0e08d 100644 --- a/packages/devui-vue/devui/table/src/table.scss +++ b/packages/devui-vue/devui/table/src/table.scss @@ -10,6 +10,7 @@ table-layout: fixed; width: 100%; border-spacing: 0; + border-collapse: separate; border: none; margin: 0; padding: 0; @@ -42,4 +43,38 @@ &--layout-auto { table-layout: auto; } + + &--sm { + tbody > tr > td { + padding: 7px 20px 8px; + + &.devui-table__checkable-cell { + padding: 8px; + } + } + + thead > tr > th.devui-table__checkable-cell { + padding: 8px; + } + } + + &--md { + tbody > tr > td { + padding: 11px 20px 12px; + } + + thead > tr > th.devui-table__checkable-cell { + padding: 8px 20px; + } + } + + &--lg { + tbody > tr > td { + padding: 15px 20px 16px; + } + + thead > tr > th.devui-table__checkable-cell { + padding: 8px 20px; + } + } } diff --git a/packages/devui-vue/docs/components/table/index.md b/packages/devui-vue/docs/components/table/index.md index e26208b735..f48c533c6b 100644 --- a/packages/devui-vue/docs/components/table/index.md +++ b/packages/devui-vue/docs/components/table/index.md @@ -88,8 +88,16 @@ export default defineComponent({ 表头背景色:
+
+ 表格大小: + + + {{ item.label }} + + +
- + @@ -105,6 +113,21 @@ export default defineComponent({ const tableLayout = ref(false); const striped = ref(false); const headerBg = ref(false); + const size = ref('sm'); + const sizeList = [ + { + label: 'Normal', + value: 'sm', + }, + { + label: 'Middle', + value: 'md', + }, + { + label: 'large', + value: 'lg', + }, + ]; const stripedTableData = ref([ { firstName: 'Mark', @@ -136,6 +159,8 @@ export default defineComponent({ stripedTableData, striped, headerBg, + size, + sizeList, tableLayout, }; }, @@ -145,12 +170,12 @@ export default defineComponent({ ``` @@ -369,21 +394,22 @@ export default defineComponent({ ### d-table 参数 -| 参数 | 类型 | 默认值 | 说明 | -| :-------------------- | :------------------ | :------ | :------------------------------ | -| data | `Array` | [] | 显示的数据 | -| striped | `Boolean` | false | 是否显示斑马纹间隔 | -| max-width | `String` | -- | 表格最大宽度 | -| max-height | `Boolean` | -- | 表格最大高度 | -| table-width | `String` | -- | 表格宽度 | -| table-height | `String` | -- | 表格高度 | -| row-hovered-highlight | `Boolean` | true | 鼠标在该行上时,高亮该行 | -| fix-header | `Boolean` | false | 固定头部 | -| checkable | `Boolean` | false | 在每行的第一列展示一个 checkbox | -| show-loading | `Boolean` | false | 显示加载动画 | -| header-bg | `Boolean` | false | 头部背景 | -| table-layout | `'fixed' \| 'auto'` | 'fixed' | 表格布局,可选值为'auto' | -| span-method | `SpanMethod` | -- | 合并单元格的计算方法 | +| 参数 | 类型 | 默认值 | 说明 | +| :-------------------- | :--------------------- | :------ | :------------------------------------------ | +| data | `array` | [] | 显示的数据 | +| striped | `boolean` | false | 是否显示斑马纹间隔 | +| size | `'sm' \| 'md' \| 'lg'` | 'sm' | 可选,表格大小,分别对应行高 40px,48px,56px | +| max-width | `string` | -- | 表格最大宽度 | +| max-height | `boolean` | -- | 表格最大高度 | +| table-width | `string` | -- | 表格宽度 | +| table-height | `string` | -- | 表格高度 | +| row-hovered-highlight | `boolean` | true | 鼠标在该行上时,高亮该行 | +| fix-header | `boolean` | false | 固定头部 | +| checkable | `boolean` | false | 在每行的第一列展示一个 checkbox | +| show-loading | `boolean` | false | 显示加载动画 | +| header-bg | `boolean` | false | 头部背景 | +| table-layout | `'fixed' \| 'auto'` | 'fixed' | 表格布局,可选值为'auto' | +| span-method | `SpanMethod` | -- | 合并单元格的计算方法 | ### d-column 参数