wip: Table component developing

This commit is contained in:
陈凯龙
2022-02-09 11:34:45 +08:00
parent 7ef216c87e
commit b271e13227
14 changed files with 1091 additions and 728 deletions

View File

@@ -1,3 +1,7 @@
import Table from './src/Table.vue'
export interface TableExpose {
setProps: (props: Recordable) => void
}
export { Table }

View File

@@ -1,13 +1,16 @@
<script lang="tsx">
import { ElTable, ElTableColumn } from 'element-plus'
import { defineComponent, PropType, ref, computed, unref } from 'vue'
import { ElTable, ElTableColumn, ElPagination } from 'element-plus'
import { defineComponent, PropType, ref, computed, unref, watch, onMounted } from 'vue'
import { propTypes } from '@/utils/propTypes'
import { setIndex } from './helper'
import { getSlot } from '@/utils/tsxHelper'
import type { TableProps } from './types'
export default defineComponent({
name: 'Table',
props: {
pageSize: propTypes.number.def(10),
currentPage: propTypes.number.def(1),
// 是否多选
selection: propTypes.bool.def(true),
// 是否所有的超出隐藏优先级低于schema中的showOverflowTooltip,
@@ -18,33 +21,105 @@ export default defineComponent({
default: () => []
},
// 是否展示分页
// pagination: {
// type: [Boolean, Object] as PropType<boolean | IObj>,
// default: false
// },
pagination: {
type: Object as PropType<Pagination>,
default: (): Pagination | undefined => undefined
},
// 仅对 type=selection 的列有效,类型为 Boolean为 true 则会在数据更新之后保留之前选中的数据(需指定 row-key
reserveSelection: propTypes.bool.def(false),
// 加载状态
loading: propTypes.bool.def(false),
// 是否叠加索引
reserveIndex: propTypes.bool.def(true),
reserveIndex: propTypes.bool.def(false),
// 对齐方式
align: propTypes.string
.validate((v: string) => ['left', 'center', 'right'].includes(v))
.def('left'),
// 表头对齐方式
headerAlign: propTypes.string
.validate((v: string) => ['left', 'center', 'right'].includes(v))
.def('left'),
// 表头对齐方式
data: {
type: Array as PropType<Recordable[]>,
default: () => []
}
},
setup(props, { attrs, slots }) {
const tableRef = ref<ComponentRef<typeof ElTable>>()
emits: ['update:pageSize', 'update:currentPage', 'register'],
setup(props, { attrs, slots, emit, expose }) {
const elTableRef = ref<ComponentRef<typeof ElTable>>()
const getProps = computed(() => props)
// 注册
onMounted(() => {
emit('register', unref(elTableRef)?.$parent, unref(elTableRef))
})
const pageSizeRef = ref(props.pageSize)
const currentPageRef = ref(props.currentPage)
// useTable传入的props
const outsideProps = ref<TableProps>({})
const mergeProps = ref<TableProps>({})
const getProps = computed(() => {
const propsObj = { ...props }
Object.assign(propsObj, unref(mergeProps))
return propsObj
})
const setProps = (props: TableProps = {}) => {
mergeProps.value = Object.assign(unref(mergeProps), props)
outsideProps.value = props
}
expose({
setProps
})
const pagination = computed(() => {
return Object.assign(
{
small: false,
background: false,
pagerCount: 7,
layout: 'sizes, prev, pager, next, jumper, ->, total',
pageSizes: [10, 20, 30, 40, 50, 100],
disabled: false,
hideOnSinglePage: false,
total: 10
},
unref(getProps).pagination
)
})
watch(
() => unref(getProps).pageSize,
(val: number) => {
pageSizeRef.value = val
}
)
watch(
() => unref(getProps).currentPage,
(val: number) => {
currentPageRef.value = val
}
)
watch(
() => pageSizeRef.value,
(val: number) => {
emit('update:pageSize', val)
}
)
watch(
() => currentPageRef.value,
(val: number) => {
emit('update:currentPage', val)
}
)
const getBindValue = computed(() => {
const bindValue: Recordable = { ...attrs, ...props }
@@ -54,25 +129,37 @@ export default defineComponent({
})
const renderTableSelection = () => {
return (
// 渲染多选
return unref(getProps).selection ? (
<ElTableColumn
type="selection"
reserveSelection={props.reserveSelection}
reserveSelection={unref(getProps).reserveSelection}
align={unref(getProps).align}
headerAlign={unref(getProps).headerAlign}
width="50"
></ElTableColumn>
)
) : undefined
}
const rnderTableColumn = (columns: TableColumn[]) => {
return (props.selection ? [renderTableSelection()] : []).concat(
return [renderTableSelection()].concat(
columns.map((v) => {
// 自定生成序号
if (v.type === 'index') {
return (
<ElTableColumn
type="index"
index={v.index ? v.index : setIndex()}
index={
v.index
? v.index
: (index) =>
setIndex(
unref(getProps).reserveIndex,
index,
unref(getProps).pageSize,
unref(getProps).currentPage
)
}
align={v.align || unref(getProps).align}
headerAlign={v.headerAlign || unref(getProps).headerAlign}
label={v.label}
@@ -91,7 +178,9 @@ export default defineComponent({
{{
default: (data: TableSlotDefault) =>
// @ts-ignore
getSlot(slots, v.field, data) || v?.formatter?.() || data.row[v.field],
getSlot(slots, v.field, data) ||
v?.formatter?.(data.row, data.column, data.row[v.field], data.$index) ||
data.row[v.field],
// @ts-ignore
header: getSlot(slots, `${v.field}-header`)
}}
@@ -106,17 +195,25 @@ export default defineComponent({
<>
<ElTable
// @ts-ignore
ref={tableRef}
ref={elTableRef}
data={unref(getProps).data}
{...getBindValue}
v-loading={unref(getProps).loading}
>
{{
default: () => rnderTableColumn(props.columns),
default: () => rnderTableColumn(unref(getProps).columns),
// @ts-ignore
append: () => getSlot(slots, 'append')
}}
</ElTable>
{unref(getProps).pagination ? (
<ElPagination
v-model:pageSize={pageSizeRef.value}
v-model:currentPage={currentPageRef.value}
class="mt-10px"
{...unref(pagination)}
></ElPagination>
) : undefined}
</>
)
}

View File

@@ -1,3 +1,8 @@
export const setIndex = () => {
return 1
export const setIndex = (reserveIndex: boolean, index: number, size: number, current: number) => {
const newIndex = index + 1
if (reserveIndex) {
return size * (current - 1) + newIndex
} else {
return newIndex
}
}

View File

@@ -0,0 +1,23 @@
export type TableProps = {
pageSize?: number
currentPage?: number
// 是否多选
selection?: boolean
// 是否所有的超出隐藏优先级低于schema中的showOverflowTooltip,
showOverflowTooltip?: boolean
// 表头
columns?: TableColumn[]
// 是否展示分页
pagination?: Pagination | undefined
// 仅对 type=selection 的列有效,类型为 Boolean为 true 则会在数据更新之后保留之前选中的数据(需指定 row-key
reserveSelection?: boolean
// 加载状态
loading?: boolean
// 是否叠加索引
reserveIndex?: boolean
// 对齐方式
align?: 'left' | 'center' | 'right'
// 表头对齐方式
headerAlign?: 'left' | 'center' | 'right'
data?: Recordable
} & Recordable