wip: Table组件重构中

This commit is contained in:
kailong321200875 2021-10-19 16:40:47 +08:00
parent 7f5ef99ccc
commit f64842462e
28 changed files with 2577 additions and 174 deletions

6
components.d.ts vendored
View File

@ -35,6 +35,7 @@ declare module 'vue' {
ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption']
ElPagination: typeof import('element-plus/es')['ElPagination']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
@ -43,6 +44,8 @@ declare module 'vue' {
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag']
@ -56,7 +59,10 @@ declare module 'vue' {
Qrcode: typeof import('./src/components/Qrcode/index.vue')['default']
Redirect: typeof import('./src/components/Redirect/index.vue')['default']
Search: typeof import('./src/components/Search/index.vue')['default']
Slot: typeof import('./src/components/Table/components/Slot.vue')['default']
SvgIcon: typeof import('./src/components/SvgIcon/index.vue')['default']
Table: typeof import('./src/components/Table/index.vue')['default']
TableColumn: typeof import('./src/components/Table/components/TableColumn.vue')['default']
}
}

View File

@ -0,0 +1,37 @@
<script lang="ts">
import { defineComponent, inject, h, PropType } from 'vue'
export default defineComponent({
name: 'Slot',
props: {
row: {
type: Object as PropType<object>,
default: () => null
},
index: {
type: Number as PropType<number>,
default: null
},
column: {
type: Object as PropType<object>,
default: () => null
},
slotName: {
type: String as PropType<string>,
default: ''
}
},
render(props: any) {
const _this: any = inject('tableRoot')
return h(
'span',
_this.slots[props.slotName]({
row: props.row,
column: props.column,
$index: props.index
})
)
}
})
</script>
<style></style>

View File

@ -0,0 +1,64 @@
<template>
<el-table-column v-bind="{ ...getItemBindValue(child) }" :prop="child.key">
<template v-for="item in child.children">
<!-- 树型数据 -->
<template v-if="item.children && item.children.length">
<table-column :key="item[item.field]" :child="item" />
</template>
<template v-else>
<el-table-column
:key="item[item.field]"
v-bind="{ ...getItemBindValue(item) }"
:prop="item.field"
>
<!-- 表头插槽 -->
<template v-if="item.slots && item.slots.header" #header="scope">
<table-slot
v-if="item.slots && item.slots.header"
:slot-name="item.slots.header"
:column="item"
:index="scope.$index"
/>
</template>
<!-- 表格内容插槽自定义 -->
<template v-if="item.slots && item.slots.default" #default="scope">
<table-slot
:slot-name="item.slots.default"
:row="scope.row"
:column="item"
:index="scope.$index"
/>
</template>
</el-table-column>
</template>
</template>
</el-table-column>
</template>
<script setup lang="ts" name="TableColumn">
import { PropType } from 'vue'
import TableSlot from './Slot.vue'
import { deepClone } from '@/utils'
defineProps({
child: {
type: Object as PropType<IObj>,
required: true
}
})
function getItemBindValue(item: any) {
const delArr: string[] = ['children']
const obj = deepClone(item)
for (const key in obj) {
if (delArr.indexOf(key) !== -1) {
delete obj[key]
}
}
return obj
}
</script>
<style></style>

View File

@ -0,0 +1,170 @@
<template>
<el-table ref="elTable" :border="true" v-bind="getBindValue" @header-dragend="headerDragend">
<!-- 多选 -->
<el-table-column
v-if="selection"
type="selection"
:reserve-selection="reserveSelection"
width="40"
/>
<template v-for="item in columns">
<!-- 自定义索引 -->
<template v-if="item.type === 'index'">
<el-table-column
:key="item[item.field]"
v-bind="{ ...getItemBindValue(item) }"
type="index"
:index="item.index"
/>
</template>
<!-- 树型数据 -->
<template v-else-if="item.children && item.children.length">
<table-column :key="item[item.field]" :child="item" />
</template>
<template v-else>
<el-table-column
:key="item[item.field]"
v-bind="{ ...getItemBindValue(item) }"
:prop="item.field"
>
<!-- 表头插槽 -->
<template v-if="item.slots && item.slots.header" #header="scope">
<table-slot
v-if="item.slots && item.slots.header"
:slot-name="item.slots.header"
:column="item"
:index="scope.$index"
/>
</template>
<!-- 表格内容插槽自定义 -->
<template v-if="item.slots && item.slots.default" #default="scope">
<table-slot
v-if="item.slots && item.slots.default"
:slot-name="item.slots.default"
:row="scope.row"
:column="item"
:index="scope.$index"
/>
</template>
</el-table-column>
</template>
</template>
</el-table>
<div v-if="pagination" class="pagination__wrap">
<el-pagination
:style="paginationStyle"
:page-sizes="[10, 20, 30, 40, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
v-bind="getPaginationBindValue"
@size-change="sizeChange"
@current-change="currentChange"
/>
</div>
</template>
<script setup lang="ts" name="ComTable">
import { PropType, computed, ref, unref, useAttrs } from 'vue'
import { deepClone } from '@/utils'
import { isObject } from '@/utils/validate'
import TableColumn from './components/TableColumn.vue'
import TableSlot from './components/Slot.vue'
const props = defineProps({
//
columns: {
type: Array as PropType<IObj[]>,
default: () => []
},
//
selection: {
type: Boolean as PropType<boolean>,
default: false
},
//
pagination: {
type: [Boolean, Object] as PropType<boolean | IObj>,
default: false
},
// type=selection Boolean true row-key
reserveSelection: {
type: Boolean as PropType<boolean>,
default: false
}
})
const attrs = useAttrs()
const elTable = ref<HTMLElement | null>(null)
function getTableRef() {
return unref(elTable as any)
}
// const _this = getCurrentInstance()
// provide('tableRoot', _this)
const getBindValue = computed((): IObj => {
const bindValue = { ...attrs, ...props } as IObj
delete bindValue.columns
return bindValue
})
function getItemBindValue(item: IObj) {
const delArr: string[] = []
const obj = deepClone(item)
for (const key in obj) {
if (delArr.indexOf(key) !== -1) {
delete obj[key]
}
}
return obj
}
const getPaginationBindValue = computed((): IObj => {
const PaginationBindValue =
props.pagination && isObject(props.pagination) ? { ...props.pagination } : {}
return PaginationBindValue
})
const paginationStyle = computed(() => {
return {
textAlign: (props.pagination && (props.pagination as IObj).position) || 'right'
}
})
function headerDragend(newWidth: number, _: number, column: IObj) {
// ing
const htmlArr = document.getElementsByClassName(column.id)
for (const v of htmlArr as any) {
if (v.firstElementChild) {
;(v.firstElementChild as any).style.width = newWidth + 'px'
}
}
}
function sizeChange(val: number) {
if (props.pagination && (props.pagination as IObj).onSizeChange) {
;(props.pagination as IObj).onSizeChange(val)
}
}
function currentChange(val: number) {
if (props.pagination && (props.pagination as IObj).onCurrentChange) {
;(props.pagination as IObj).onCurrentChange(val)
}
}
defineExpose({
getTableRef
})
</script>
<style lang="less" scoped>
.pagination__wrap {
padding: 10px;
margin-top: 15px;
background: #fff;
}
</style>

View File

@ -3,10 +3,12 @@ import SvgIcon from './SvgIcon/index.vue' // svg组件
import ComSearch from './Search/index.vue' // search组件
import ComDialog from './Dialog/index.vue' // dialog组件
import ComDetail from './Detail/index.vue' // detail组件
import ComTable from './Table/index.vue' // table组件
export function setupGlobCom(app: App<Element>): void {
app.component('SvgIcon', SvgIcon)
app.component('ComSearch', ComSearch)
app.component('ComDialog', ComDialog)
app.component('ComDetail', ComDetail)
app.component('ComTable', ComTable)
}

View File

@ -216,182 +216,190 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
meta: {
title: '文字高亮'
}
},
{
path: 'watermark',
component: () => import('_v/components-demo/watermark/index.vue'),
name: 'WatermarkDemo',
meta: {
title: '水印'
}
}
]
},
// {
// path: '/table-demo',
// component: Layout,
// redirect: '/table-demo/basic-table',
// name: 'TableDemo',
// meta: {
// title: '表格',
// icon: 'table',
// alwaysShow: true
// },
// children: [
// {
// path: 'basic-table',
// component: () => import('_v/table-demo/basic-table/index.vue'),
// name: 'BasicTable',
// meta: {
// title: '基础表格'
// }
// },
// {
// path: 'page-table',
// component: () => import('_v/table-demo/page-table/index.vue'),
// name: 'PageTable',
// meta: {
// title: '分页表格'
// }
// },
// {
// path: 'stripe-table',
// component: () => import('_v/table-demo/stripe-table/index.vue'),
// name: 'StripeTable',
// meta: {
// title: '带斑马纹表格'
// }
// },
// {
// path: 'border-table',
// component: () => import('_v/table-demo/border-table/index.vue'),
// name: 'BorderTable',
// meta: {
// title: '带边框表格'
// }
// },
// {
// path: 'state-table',
// component: () => import('_v/table-demo/state-table/index.vue'),
// name: 'StateTable',
// meta: {
// title: '带状态表格'
// }
// },
// {
// path: 'fixed-header',
// component: () => import('_v/table-demo/fixed-header/index.vue'),
// name: 'FixedHeader',
// meta: {
// title: '固定表头'
// }
// },
// {
// path: 'fixed-column',
// component: () => import('_v/table-demo/fixed-column/index.vue'),
// name: 'FixedColumn',
// meta: {
// title: '固定列'
// }
// },
// {
// path: 'fixed-column-header',
// component: () => import('_v/table-demo/fixed-column-header/index.vue'),
// name: 'FixedColumnHeader',
// meta: {
// title: '固定列和表头'
// }
// },
// {
// path: 'fluid-height',
// component: () => import('_v/table-demo/fluid-height/index.vue'),
// name: 'FluidHeight',
// meta: {
// title: '流体高度'
// }
// },
// {
// path: 'multi-header',
// component: () => import('_v/table-demo/multi-header/index.vue'),
// name: 'MultiHeader',
// meta: {
// title: '多级表头'
// }
// },
// {
// path: 'single-choice',
// component: () => import('_v/table-demo/single-choice/index.vue'),
// name: 'SingleChoice',
// meta: {
// title: '单选'
// }
// },
// {
// path: 'multiple-choice',
// component: () => import('_v/table-demo/multiple-choice/index.vue'),
// name: 'MultipleChoice',
// meta: {
// title: '多选'
// }
// },
// {
// path: 'sort-table',
// component: () => import('_v/table-demo/sort-table/index.vue'),
// name: 'SortTable',
// meta: {
// title: '排序'
// }
// },
// {
// path: 'screen-table',
// component: () => import('_v/table-demo/screen-table/index.vue'),
// name: 'ScreenTable',
// meta: {
// title: '筛选'
// }
// },
// {
// path: 'expand-row',
// component: () => import('_v/table-demo/expand-row/index.vue'),
// name: 'ExpandRow',
// meta: {
// title: '展开行'
// }
// },
// {
// path: 'tree-and-load',
// component: () => import('_v/table-demo/tree-and-load/index.vue'),
// name: 'TreeAndLoad',
// meta: {
// title: '树形数据与懒加载'
// }
// },
// {
// path: 'custom-header',
// component: () => import('_v/table-demo/custom-header/index.vue'),
// name: 'CustomHeader',
// meta: {
// title: '自定义表头'
// }
// },
// {
// path: 'total-table',
// component: () => import('_v/table-demo/total-table/index.vue'),
// name: 'TotalTable',
// meta: {
// title: '表尾合计行'
// }
// },
// {
// path: 'merge-table',
// component: () => import('_v/table-demo/merge-table/index.vue'),
// name: 'MergeTable',
// meta: {
// title: '合并行或列'
// }
// },
// {
// path: 'custom-index',
// component: () => import('_v/table-demo/custom-index/index.vue'),
// name: 'CustomIndex',
// meta: {
// title: '自定义索引'
// }
// }
// ]
// },
{
path: '/table-demo',
component: Layout,
redirect: '/table-demo/basic-table',
name: 'TableDemo',
meta: {
title: '表格',
icon: 'table',
alwaysShow: true
},
children: [
{
path: 'basic-table',
component: () => import('_v/table-demo/basic-table/index.vue'),
name: 'BasicTable',
meta: {
title: '基础表格'
}
}
// {
// path: 'page-table',
// component: () => import('_v/table-demo/page-table/index.vue'),
// name: 'PageTable',
// meta: {
// title: '分页表格'
// }
// },
// {
// path: 'stripe-table',
// component: () => import('_v/table-demo/stripe-table/index.vue'),
// name: 'StripeTable',
// meta: {
// title: '带斑马纹表格'
// }
// },
// {
// path: 'border-table',
// component: () => import('_v/table-demo/border-table/index.vue'),
// name: 'BorderTable',
// meta: {
// title: '带边框表格'
// }
// },
// {
// path: 'state-table',
// component: () => import('_v/table-demo/state-table/index.vue'),
// name: 'StateTable',
// meta: {
// title: '带状态表格'
// }
// },
// {
// path: 'fixed-header',
// component: () => import('_v/table-demo/fixed-header/index.vue'),
// name: 'FixedHeader',
// meta: {
// title: '固定表头'
// }
// },
// {
// path: 'fixed-column',
// component: () => import('_v/table-demo/fixed-column/index.vue'),
// name: 'FixedColumn',
// meta: {
// title: '固定列'
// }
// },
// {
// path: 'fixed-column-header',
// component: () => import('_v/table-demo/fixed-column-header/index.vue'),
// name: 'FixedColumnHeader',
// meta: {
// title: '固定列和表头'
// }
// },
// {
// path: 'fluid-height',
// component: () => import('_v/table-demo/fluid-height/index.vue'),
// name: 'FluidHeight',
// meta: {
// title: '流体高度'
// }
// },
// {
// path: 'multi-header',
// component: () => import('_v/table-demo/multi-header/index.vue'),
// name: 'MultiHeader',
// meta: {
// title: '多级表头'
// }
// },
// {
// path: 'single-choice',
// component: () => import('_v/table-demo/single-choice/index.vue'),
// name: 'SingleChoice',
// meta: {
// title: '单选'
// }
// },
// {
// path: 'multiple-choice',
// component: () => import('_v/table-demo/multiple-choice/index.vue'),
// name: 'MultipleChoice',
// meta: {
// title: '多选'
// }
// },
// {
// path: 'sort-table',
// component: () => import('_v/table-demo/sort-table/index.vue'),
// name: 'SortTable',
// meta: {
// title: '排序'
// }
// },
// {
// path: 'screen-table',
// component: () => import('_v/table-demo/screen-table/index.vue'),
// name: 'ScreenTable',
// meta: {
// title: '筛选'
// }
// },
// {
// path: 'expand-row',
// component: () => import('_v/table-demo/expand-row/index.vue'),
// name: 'ExpandRow',
// meta: {
// title: '展开行'
// }
// },
// {
// path: 'tree-and-load',
// component: () => import('_v/table-demo/tree-and-load/index.vue'),
// name: 'TreeAndLoad',
// meta: {
// title: '树形数据与懒加载'
// }
// },
// {
// path: 'custom-header',
// component: () => import('_v/table-demo/custom-header/index.vue'),
// name: 'CustomHeader',
// meta: {
// title: '自定义表头'
// }
// },
// {
// path: 'total-table',
// component: () => import('_v/table-demo/total-table/index.vue'),
// name: 'TotalTable',
// meta: {
// title: '表尾合计行'
// }
// },
// {
// path: 'merge-table',
// component: () => import('_v/table-demo/merge-table/index.vue'),
// name: 'MergeTable',
// meta: {
// title: '合并行或列'
// }
// },
// {
// path: 'custom-index',
// component: () => import('_v/table-demo/custom-index/index.vue'),
// name: 'CustomIndex',
// meta: {
// title: '自定义索引'
// }
// }
]
},
// {
// path: '/directives-demo',
// component: Layout,

View File

@ -129,7 +129,7 @@ export function exportFile(response: AxiosResponse) {
? response.headers['content-disposition'].split(';')[1].split('=')[1]
: 'test'
)
const blob = new Blob([response.data], {
const blob = new Blob([response.data as Blob], {
type: response.headers['content-type']
})
if (typeof (window.navigator as any).msSaveBlob !== 'undefined') {

View File

@ -0,0 +1,26 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="useWatermark为整个系统提供水印功能。"
type="info"
style="margin-bottom: 20px"
/>
<el-button type="primary" @click="setWatermark('vue-element-plus-admin')">创建水印</el-button>
<el-button type="danger" @click="clear">清除水印</el-button>
<el-button type="warning" @click="setWatermark('vue-element-plus-admin-new')">
重置水印
</el-button>
</div>
</template>
<script setup lang="ts" name="Watermark">
import { onBeforeUnmount } from 'vue'
import { useWatermark } from '@/hooks/web/useWatermark'
const { setWatermark, clear } = useWatermark()
onBeforeUnmount(() => {
clear()
})
</script>

View File

@ -0,0 +1,61 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 基础表格"
type="info"
style="margin-bottom: 20px"
/>
<com-table v-loading="loading" :columns="columns" :data="tableData" />
</div>
</template>
<script setup lang="ts" name="BasicTable">
import { ref } from 'vue'
const columns = [
{
field: 'date',
label: '日期'
},
{
field: 'name',
label: '姓名'
},
{
field: 'address',
label: '地址'
}
]
const tableData = [
{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
},
{
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
},
{
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}
]
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
</script>
<style></style>

View File

@ -0,0 +1,61 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 带边框表格"
type="info"
style="margin-bottom: 20px"
/>
<com-table v-loading="loading" :columns="columns" :data="tableData" border />
</div>
</template>
<script setup lang="ts" name="BorderTable">
import { ref } from 'vue'
const columns = [
{
field: 'date',
label: '日期'
},
{
field: 'name',
label: '姓名'
},
{
field: 'address',
label: '地址'
}
]
const tableData = [
{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
},
{
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
},
{
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}
]
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
</script>
<style></style>

View File

@ -0,0 +1,91 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 自定义表头"
type="info"
style="margin-bottom: 20px"
/>
<com-table
v-loading="loading"
:columns="columns"
:data="
tableData.filter(
(data) => !search || data.name.toLowerCase().includes(search.toLowerCase())
)
"
>
<template #actionHeader>
<el-input v-model="search" size="mini" placeholder="输入关键字搜索" />
</template>
<template #action="scope">
<el-button size="mini" @click="handleEdit(scope.$index, scope.row)">Edit</el-button>
<el-button size="mini" type="danger" @click="handleDelete(scope.$index, scope.row)"
>Delete</el-button
>
</template>
</com-table>
</div>
</template>
<script setup lang="ts" name="CustomHeader">
import { ref } from 'vue'
const columns = [
{
field: 'date',
label: '日期'
},
{
field: 'name',
label: '姓名'
},
{
field: 'action',
slots: {
header: 'actionHeader',
default: 'action'
}
}
]
const tableData = [
{
date: '2016-05-02',
name: '王小虎1',
address: '上海市普陀区金沙江路 1518 弄'
},
{
date: '2016-05-04',
name: '王小虎2',
address: '上海市普陀区金沙江路 1517 弄'
},
{
date: '2016-05-01',
name: '王小虎3',
address: '上海市普陀区金沙江路 1519 弄'
},
{
date: '2016-05-03',
name: '王小虎4',
address: '上海市普陀区金沙江路 1516 弄'
}
]
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
const search = ref<string>('')
function handleEdit(index: number, row: any) {
console.log(index, row)
}
function handleDelete(index: number, row: any) {
console.log(index, row)
}
</script>
<style></style>

View File

@ -0,0 +1,68 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 自定义索引"
type="info"
style="margin-bottom: 20px"
/>
<com-table v-loading="loading" :columns="columns" :data="tableData" />
</div>
</template>
<script setup lang="ts" name="CustomIndex">
import { ref } from 'vue'
const tableData = [
{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
},
{
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
},
{
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}
]
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
const columns = ref<any[]>([
{
field: 'index',
type: 'index',
index: (index: number) => {
return index * 2
}
},
{
field: 'date',
label: '日期'
},
{
field: 'name',
label: '姓名'
},
{
field: 'address',
label: '地址'
}
])
</script>
<style></style>

View File

@ -0,0 +1,125 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 展开行"
type="info"
style="margin-bottom: 20px"
/>
<com-table ref="multipleTable" v-loading="loading" :columns="columns" :data="tableData">
<template #id="scope">
<el-form label-position="left" inline class="demo-table-expand">
<el-form-item label="商品名称">
<span>{{ scope.row.name }}</span>
</el-form-item>
<el-form-item label="所属店铺">
<span>{{ scope.row.shop }}</span>
</el-form-item>
<el-form-item label="商品 ID">
<span>{{ scope.row.id }}</span>
</el-form-item>
<el-form-item label="店铺 ID">
<span>{{ scope.row.shopId }}</span>
</el-form-item>
<el-form-item label="商品分类">
<span>{{ scope.row.category }}</span>
</el-form-item>
<el-form-item label="店铺地址">
<span>{{ scope.row.address }}</span>
</el-form-item>
<el-form-item label="商品描述">
<span>{{ scope.row.desc }}</span>
</el-form-item>
</el-form>
</template>
</com-table>
</div>
</template>
<script setup lang="ts" name="ExpandRow">
import { ref } from 'vue'
const columns = [
{
field: 'id',
type: 'expand',
slots: {
default: 'id'
}
},
{
field: 'id',
label: '商品ID'
},
{
field: 'name',
label: '商品名称'
},
{
field: 'desc',
label: '描述'
}
]
const tableData = [
{
id: '12987122',
name: '好滋好味鸡蛋仔',
category: '江浙小吃、小吃零食',
desc: '荷兰优质淡奶,奶香浓而不腻',
address: '上海市普陀区真北路',
shop: '王小虎夫妻店',
shopId: '10333'
},
{
id: '12987123',
name: '好滋好味鸡蛋仔',
category: '江浙小吃、小吃零食',
desc: '荷兰优质淡奶,奶香浓而不腻',
address: '上海市普陀区真北路',
shop: '王小虎夫妻店',
shopId: '10333'
},
{
id: '12987125',
name: '好滋好味鸡蛋仔',
category: '江浙小吃、小吃零食',
desc: '荷兰优质淡奶,奶香浓而不腻',
address: '上海市普陀区真北路',
shop: '王小虎夫妻店',
shopId: '10333'
},
{
id: '12987126',
name: '好滋好味鸡蛋仔',
category: '江浙小吃、小吃零食',
desc: '荷兰优质淡奶,奶香浓而不腻',
address: '上海市普陀区真北路',
shop: '王小虎夫妻店',
shopId: '10333'
}
]
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
</script>
<style lang="less" scoped>
:deep(.demo-table-expand) {
font-size: 0;
label {
width: 90px;
color: #99a9bf;
}
.el-form-item {
width: 50%;
margin-right: 0;
margin-bottom: 0;
}
}
</style>

View File

@ -0,0 +1,149 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 固定列和表头"
type="info"
style="margin-bottom: 20px"
/>
<com-table
v-loading="loading"
:columns="columns"
:data="tableData"
border
height="250"
style="width: 820px"
>
<template #action="scope">
<el-button type="text" size="small" @click="handleClick(scope.row)">查看</el-button>
<el-button type="text" size="small">编辑</el-button>
</template>
</com-table>
</div>
</template>
<script setup lang="ts" name="FixedColumnHeader">
import { ref } from 'vue'
const columns = [
{
field: 'date',
label: '日期',
fixed: true,
width: '150'
},
{
field: 'name',
label: '姓名',
width: '120'
},
{
field: 'province',
label: '省份',
width: '120'
},
{
field: 'city',
label: '市区',
width: '120'
},
{
field: 'address',
label: '地址',
width: '300'
},
{
field: 'zip',
label: '邮编',
width: '120'
},
{
field: 'action',
label: '操作',
width: '100',
fixed: 'right',
slots: {
default: 'action'
}
}
]
const tableData = [
{
date: '2016-05-02',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
},
{
date: '2016-05-04',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1517 弄',
zip: 200333
},
{
date: '2016-05-01',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1519 弄',
zip: 200333
},
{
date: '2016-05-03',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1516 弄',
zip: 200333
},
{
date: '2016-05-02',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
},
{
date: '2016-05-04',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1517 弄',
zip: 200333
},
{
date: '2016-05-01',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1519 弄',
zip: 200333
},
{
date: '2016-05-03',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1516 弄',
zip: 200333
}
]
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
function handleClick(row: any) {
console.log(row)
}
</script>
<style></style>

View File

@ -0,0 +1,110 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 固定列"
type="info"
style="margin-bottom: 20px"
/>
<com-table v-loading="loading" :columns="columns" :data="tableData" border style="width: 820px">
<template #action="scope">
<el-button type="text" size="small" @click="handleClick(scope.row)">查看</el-button>
<el-button type="text" size="small">编辑</el-button>
</template>
</com-table>
</div>
</template>
<script setup lang="ts" name="FixedColumn">
import { ref } from 'vue'
const columns = [
{
field: 'date',
label: '日期',
fixed: true,
width: '150'
},
{
field: 'name',
label: '姓名',
width: '120'
},
{
field: 'province',
label: '省份',
width: '120'
},
{
field: 'city',
label: '市区',
width: '120'
},
{
field: 'address',
label: '地址',
width: '300'
},
{
field: 'zip',
label: '邮编',
width: '120'
},
{
field: 'action',
label: '操作',
width: '100',
fixed: 'right',
slots: {
default: 'action'
}
}
]
const tableData = [
{
date: '2016-05-02',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
},
{
date: '2016-05-04',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1517 弄',
zip: 200333
},
{
date: '2016-05-01',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1519 弄',
zip: 200333
},
{
date: '2016-05-03',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1516 弄',
zip: 200333
}
]
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
function handleClick(row: any) {
console.log(row)
}
</script>
<style></style>

View File

@ -0,0 +1,81 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 固定表头"
type="info"
style="margin-bottom: 20px"
/>
<com-table v-loading="loading" :columns="columns" :data="tableData" height="250" border />
</div>
</template>
<script setup lang="ts" name="FixedHeader">
import { ref } from 'vue'
const columns = [
{
field: 'date',
label: '日期'
},
{
field: 'name',
label: '姓名'
},
{
field: 'address',
label: '地址'
}
]
const tableData = [
{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
},
{
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
},
{
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
},
{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
},
{
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
},
{
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}
]
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
</script>
<style></style>

View File

@ -0,0 +1,147 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 流体高度"
type="info"
style="margin-bottom: 20px"
/>
<com-table
v-loading="loading"
:columns="columns"
:data="tableData"
border
max-height="250"
style="width: 820px"
>
<template #action="scope">
<el-button type="text" size="small" @click="deleteRow(scope.$index)">移除</el-button>
</template>
</com-table>
</div>
</template>
<script setup lang="ts" name="FluidHeight">
import { ref } from 'vue'
const columns = [
{
field: 'date',
label: '日期',
fixed: true,
width: '150'
},
{
field: 'name',
label: '姓名',
width: '120'
},
{
field: 'province',
label: '省份',
width: '120'
},
{
field: 'city',
label: '市区',
width: '120'
},
{
field: 'address',
label: '地址',
width: '300'
},
{
field: 'zip',
label: '邮编',
width: '120'
},
{
field: 'action',
label: '操作',
width: '100',
fixed: 'right',
slots: {
default: 'action'
}
}
]
const tableData = ref<IObj[]>([
{
date: '2016-05-02',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
},
{
date: '2016-05-04',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1517 弄',
zip: 200333
},
{
date: '2016-05-01',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1519 弄',
zip: 200333
},
{
date: '2016-05-03',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1516 弄',
zip: 200333
},
{
date: '2016-05-02',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
},
{
date: '2016-05-04',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1517 弄',
zip: 200333
},
{
date: '2016-05-01',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1519 弄',
zip: 200333
},
{
date: '2016-05-03',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1516 弄',
zip: 200333
}
])
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
function deleteRow(index: number) {
tableData.value.splice(index, 1)
}
</script>
<style></style>

View File

@ -0,0 +1,151 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 合并行或列"
type="info"
style="margin-bottom: 20px"
/>
<com-table
v-loading="loading"
:columns="columns"
:data="tableData"
:span-method="arraySpanMethod"
border
/>
<com-table
v-loading="loading"
:columns="columns1"
:data="tableData"
:span-method="objectSpanMethod"
border
style="margin-top: 20px"
/>
</div>
</template>
<script setup lang="ts" name="MergeTable">
import { ref } from 'vue'
const columns = [
{
field: 'id',
label: 'ID'
},
{
field: 'name',
label: '姓名'
},
{
field: 'amount1',
label: '数值1',
sortable: true
},
{
field: 'amount2',
label: '数值2',
sortable: true
},
{
field: 'amount3',
label: '数值4',
sortable: true
}
]
const columns1 = [
{
field: 'id',
label: 'ID'
},
{
field: 'name',
label: '姓名'
},
{
field: 'amount1',
label: '数值1'
},
{
field: 'amount2',
label: '数值2'
},
{
field: 'amount3',
label: '数值4'
}
]
const tableData = [
{
id: '12987122',
name: '王小虎',
amount1: '234',
amount2: '3.2',
amount3: 10
},
{
id: '12987123',
name: '王小虎',
amount1: '165',
amount2: '4.43',
amount3: 12
},
{
id: '12987124',
name: '王小虎',
amount1: '324',
amount2: '1.9',
amount3: 9
},
{
id: '12987125',
name: '王小虎',
amount1: '621',
amount2: '2.2',
amount3: 17
},
{
id: '12987126',
name: '王小虎',
amount1: '539',
amount2: '4.1',
amount3: 15
}
]
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
function arraySpanMethod({ rowIndex, columnIndex }: any) {
if (rowIndex % 2 === 0) {
if (columnIndex === 0) {
return [1, 2]
} else if (columnIndex === 1) {
return [0, 0]
}
}
}
function objectSpanMethod({ rowIndex, columnIndex }: any) {
if (columnIndex === 0) {
if (rowIndex % 2 === 0) {
return {
rowspan: 2,
colspan: 1
}
} else {
return {
rowspan: 0,
colspan: 0
}
}
}
}
</script>
<style></style>

View File

@ -0,0 +1,145 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 多级表头"
type="info"
style="margin-bottom: 20px"
/>
<com-table v-loading="loading" :columns="columns" :data="tableData">
<template #address="scope"> 地址是: {{ scope.row.address }} </template>
<template #action="scope">
<el-button type="text" size="small" @click="deleteRow(scope.$index)">移除</el-button>
</template>
</com-table>
</div>
</template>
<script setup lang="ts" name="MultiHeader">
import { ref } from 'vue'
const columns = [
{
field: 'date',
label: '日期',
fixed: true,
width: '150'
},
{
label: '配送信息',
children: [
{
field: 'name',
label: '姓名',
width: '120'
},
{
label: '地址',
children: [
{
field: 'province',
label: '省份',
width: '120'
},
{
field: 'city',
label: '市区',
width: '120'
},
{
field: 'address',
label: '地址',
slots: {
default: 'address'
}
},
{
field: 'zip',
label: '邮编',
width: '120'
}
]
}
]
},
{
field: 'action',
label: '操作',
width: '100',
slots: {
default: 'action'
}
}
]
const tableData = ref<any[]>([
{
date: '2016-05-03',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
},
{
date: '2016-05-02',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
},
{
date: '2016-05-04',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
},
{
date: '2016-05-01',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
},
{
date: '2016-05-08',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
},
{
date: '2016-05-06',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
},
{
date: '2016-05-07',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
}
])
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
function deleteRow(index: number) {
tableData.value.splice(index, 1)
}
</script>
<style></style>

View File

@ -0,0 +1,90 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 多选"
type="info"
style="margin-bottom: 20px"
/>
<com-table
ref="multipleTable"
v-loading="loading"
selection
:columns="columns"
:data="tableData"
@selection-change="handleSelectionChange"
/>
<div style="margin-top: 20px">
<el-button @click="toggleSelection([tableData[1], tableData[2]])"
>切换第二第三行的选中状态</el-button
>
<el-button @click="toggleSelection()">取消选择</el-button>
</div>
</div>
</template>
<script setup lang="ts" name="MultipleChoice">
import { ref, unref } from 'vue'
const columns = [
{
field: 'date',
label: '日期'
},
{
field: 'name',
label: '姓名'
},
{
field: 'address',
label: '地址'
}
]
const tableData = [
{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
},
{
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
},
{
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}
]
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
const multipleTable = ref<HTMLElement | null>(null)
function toggleSelection(rows?: any[]) {
const multipleTableRef = unref(multipleTable as any).getTableRef()
if (rows) {
rows.forEach((row) => {
multipleTableRef.toggleRowSelection(row)
})
} else {
multipleTableRef.clearSelection()
}
}
function handleSelectionChange(val: any) {
console.log(val)
}
</script>
<style></style>

View File

@ -0,0 +1,79 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 分页表格"
type="info"
style="margin-bottom: 20px"
/>
<com-table
v-loading="loading"
:columns="columns"
:data="tableData"
:pagination="{
currentPage: 1,
total: 400,
onSizeChange: handleSizeChange,
onCurrentChange: handleCurrentChange
}"
/>
</div>
</template>
<script setup lang="ts" name="PageTable">
import { ref } from 'vue'
const columns = [
{
field: 'date',
label: '日期'
},
{
field: 'name',
label: '姓名'
},
{
field: 'address',
label: '地址'
}
]
const tableData = [
{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
},
{
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
},
{
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}
]
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
function handleSizeChange(val: number) {
console.log(val)
}
function handleCurrentChange(val: number) {
console.log(val)
}
</script>
<style></style>

View File

@ -0,0 +1,124 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 筛选"
type="info"
style="margin-bottom: 20px"
/>
<el-button @click="resetDateFilter">清除日期过滤器</el-button>
<el-button @click="clearFilter">清除所有过滤器</el-button>
<com-table
ref="filterTable"
v-loading="loading"
row-key="date"
:columns="columns"
:data="tableData"
:default-sort="{ prop: 'date', order: 'descending' }"
>
<template #tag="scope">
<el-tag
:type="(scope.row.tag === '家' ? 'primary' : 'success') as any"
disable-transitions
>{{ scope.row.tag }}</el-tag
>
</template>
</com-table>
</div>
</template>
<script setup lang="ts" name="ScreenTable">
import { ref, unref } from 'vue'
const tableData = [
{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄',
tag: '家'
},
{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄',
tag: '公司'
},
{
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄',
tag: '家'
},
{
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄',
tag: '公司'
}
]
const filterTable = ref<HTMLElement | null>(null)
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
const columns = ref<any[]>([
{
field: 'date',
label: '日期',
sortable: true,
width: '180',
columnKey: 'date',
filters: [
{ text: '2016-05-01', value: '2016-05-01' },
{ text: '2016-05-02', value: '2016-05-02' },
{ text: '2016-05-03', value: '2016-05-03' },
{ text: '2016-05-04', value: '2016-05-04' }
],
filterMethod: filterHandler
},
{
field: 'name',
label: '姓名',
sortable: true
},
{
field: 'address',
label: '地址'
},
{
field: 'tag',
label: '标签',
filters: [
{ text: '家', value: '家' },
{ text: '公司', value: '公司' }
],
filterMethod: filterTag,
filterPlacement: 'bottom-end',
slots: {
default: 'tag'
}
}
])
function resetDateFilter() {
const filterTableRef = unref(filterTable as any).getTableRef()
filterTableRef.clearFilter('date')
}
function clearFilter() {
const filterTableRef = unref(filterTable as any).getTableRef()
filterTableRef.clearFilter()
}
function filterTag(value: string, row: any) {
return row.tag === value
}
function filterHandler(value: string, row: any, column: any) {
const property = column['property']
return row[property] === value
}
</script>
<style></style>

View File

@ -0,0 +1,82 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 单选"
type="info"
style="margin-bottom: 20px"
/>
<com-table
ref="singleTable"
v-loading="loading"
highlight-current-row
:columns="columns"
:data="tableData"
@current-change="handleCurrentChange"
/>
<div style="margin-top: 20px">
<el-button @click="setCurrent(tableData[1])">选中第二行</el-button>
<el-button @click="setCurrent()">取消选择</el-button>
</div>
</div>
</template>
<script setup lang="ts" name="SingleChoice">
import { ref, unref } from 'vue'
const columns = [
{
field: 'date',
label: '日期'
},
{
field: 'name',
label: '姓名'
},
{
field: 'address',
label: '地址'
}
]
const tableData = [
{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
},
{
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
},
{
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}
]
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
const singleTable = ref<HTMLElement | null>(null)
function setCurrent(row?: any) {
const singleTableRef = unref(singleTable as any).getTableRef()
singleTableRef.setCurrentRow(row)
}
function handleCurrentChange(val: any) {
console.log(val)
}
</script>
<style></style>

View File

@ -0,0 +1,69 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 排序"
type="info"
style="margin-bottom: 20px"
/>
<com-table
ref="multipleTable"
v-loading="loading"
:columns="columns"
:data="tableData"
:default-sort="{ prop: 'date', order: 'descending' }"
/>
</div>
</template>
<script setup lang="ts" name="SortTable">
import { ref } from 'vue'
const columns = [
{
field: 'date',
label: '日期',
sortable: true
},
{
field: 'name',
label: '姓名',
sortable: true
},
{
field: 'address',
label: '地址'
}
]
const tableData = [
{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
},
{
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
},
{
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}
]
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
</script>
<style></style>

View File

@ -0,0 +1,85 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 带状态表格"
type="info"
style="margin-bottom: 20px"
/>
<com-table
v-loading="loading"
:columns="columns"
:data="tableData"
:row-class-name="tableRowClassName"
/>
</div>
</template>
<script setup lang="ts" name="StateTable">
import { ref } from 'vue'
const columns = [
{
field: 'date',
label: '日期'
},
{
field: 'name',
label: '姓名'
},
{
field: 'address',
label: '地址'
}
]
const tableData = [
{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
},
{
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
},
{
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}
]
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
function tableRowClassName({ rowIndex }: any) {
if (rowIndex === 1) {
return 'warning-row'
} else if (rowIndex === 3) {
return 'success-row'
}
return ''
}
</script>
<style lang="less" scoped>
:deep(.el-table) {
.warning-row {
background: oldlace;
}
.success-row {
background: #f0f9eb;
}
}
</style>

View File

@ -0,0 +1,61 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 带斑马纹表格"
type="info"
style="margin-bottom: 20px"
/>
<com-table v-loading="loading" :columns="columns" :data="tableData" stripe />
</div>
</template>
<script setup lang="ts" name="StripeTable">
import { ref } from 'vue'
const columns = [
{
field: 'date',
label: '日期'
},
{
field: 'name',
label: '姓名'
},
{
field: 'address',
label: '地址'
}
]
const tableData = [
{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
},
{
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
},
{
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}
]
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
</script>
<style></style>

View File

@ -0,0 +1,148 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 表尾合计行"
type="info"
style="margin-bottom: 20px"
/>
<com-table v-loading="loading" :columns="columns" :data="tableData" border show-summary />
<com-table
v-loading="loading"
:columns="columns1"
:data="tableData"
border
height="200"
:summary-method="getSummaries"
show-summary
style="margin-top: 20px"
/>
</div>
</template>
<script setup lang="ts" name="TotalTable">
import { ref } from 'vue'
const columns = [
{
field: 'id',
label: 'ID'
},
{
field: 'name',
label: '姓名'
},
{
field: 'amount1',
label: '数值1',
sortable: true
},
{
field: 'amount2',
label: '数值2',
sortable: true
},
{
field: 'amount3',
label: '数值4',
sortable: true
}
]
const columns1 = [
{
field: 'id',
label: 'ID'
},
{
field: 'name',
label: '姓名'
},
{
field: 'amount1',
label: '数值1'
},
{
field: 'amount2',
label: '数值2'
},
{
field: 'amount3',
label: '数值4'
}
]
const tableData = [
{
id: '12987122',
name: '王小虎',
amount1: '234',
amount2: '3.2',
amount3: 10
},
{
id: '12987123',
name: '王小虎',
amount1: '165',
amount2: '4.43',
amount3: 12
},
{
id: '12987124',
name: '王小虎',
amount1: '324',
amount2: '1.9',
amount3: 9
},
{
id: '12987125',
name: '王小虎',
amount1: '621',
amount2: '2.2',
amount3: 17
},
{
id: '12987126',
name: '王小虎',
amount1: '539',
amount2: '4.1',
amount3: 15
}
]
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
function getSummaries(param: any) {
const { columns, data } = param
const sums: any[] = []
columns.forEach((column: any, index: number) => {
if (index === 0) {
sums[index] = '总价'
return
}
const values = data.map((item: any) => Number(item[column.property]))
if (!values.every((value: number) => isNaN(value))) {
sums[index] = values.reduce((prev: number, curr: number) => {
const value = Number(curr)
if (!isNaN(value)) {
return prev + curr
} else {
return prev
}
}, 0)
sums[index] += ' 元'
} else {
sums[index] = 'N/A'
}
})
return sums
}
</script>
<style></style>

View File

@ -0,0 +1,163 @@
<template>
<div>
<el-alert
effect="dark"
:closable="false"
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 树形数据与懒加载"
type="info"
style="margin-bottom: 20px"
/>
<com-table
v-loading="loading"
:columns="columns"
:data="tableData"
row-key="id"
border
default-expand-all
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
/>
<com-table
v-loading="loading"
:columns="columns1"
:data="tableData1"
row-key="id"
border
lazy
:load="load"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
style="margin-top: 20px"
/>
</div>
</template>
<script setup lang="ts" name="TreeAndLoad">
import { ref } from 'vue'
const columns = [
{
field: 'date',
label: '日期',
sortable: true
},
{
field: 'name',
label: '姓名',
sortable: true
},
{
field: 'address',
label: '地址'
}
]
const columns1 = [
{
field: 'date',
label: '日期'
},
{
field: 'name',
label: '姓名'
},
{
field: 'address',
label: '地址'
}
]
const tableData = [
{
id: 1,
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 2,
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
},
{
id: 3,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄',
children: [
{
id: 31,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
},
{
id: 32,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}
]
},
{
id: 4,
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}
]
const tableData1 = [
{
id: 1,
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 2,
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
},
{
id: 3,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄',
hasChildren: true
},
{
id: 4,
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}
]
const loading = ref<boolean>(true)
setTimeout(() => {
loading.value = false
}, 1000)
function load(_: any, __: any, resolve: Function) {
setTimeout(() => {
resolve([
{
id: 31,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
},
{
id: 32,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}
])
}, 1000)
}
</script>
<style></style>