Appearance
表格组件的封装
TIP
这个表格组件只是一个封装,具体实现请自行实现。
CustomTable.vue
组件
vue
<template>
<div class="custom-table">
<el-table
:data="tableData"
:border="border"
:stripe="stripe"
:highlight-current-row="highlightCurrentRow"
:row-key="rowKey"
:max-height="maxHeight"
@selection-change="handleSelectionChange"
@row-click="handleRowClick"
@row-dblclick="handleRowDblclick"
@sort-change="handleSortChange"
:row-class-name="rowClassName"
>
<!-- 复选框列 -->
<el-table-column
v-if="selection"
type="selection"
width="55"
></el-table-column>
<!-- 序号列 -->
<el-table-column
v-if="showIndex"
type="index"
:label="indexLabel"
:width="indexWidth"
></el-table-column>
<!-- 自定义列 -->
<el-table-column
v-for="column in columns"
:key="column.prop"
:prop="column.prop"
:label="column.label"
:width="column.width"
:min-width="column.minWidth"
:fixed="column.fixed"
:sortable="column.sortable"
:align="column.align || 'left'"
:show-overflow-tooltip="column.showOverflowTooltip || true"
>
<!-- 插槽支持 -->
<template #default="scope">
<slot
:name="`column-${column.prop}`"
:row="scope.row"
:index="scope.$index"
>
{{ scope.row[column.prop] }}
</slot>
</template>
</el-table-column>
<!-- 操作列 -->
<el-table-column
v-if="operationOptions && operationOptions.length > 0"
:label="operationLabel"
:width="operationWidth"
align="center"
>
<template #default="scope">
<el-button
v-for="option in operationOptions"
:key="option.label"
:type="option.type || 'text'"
:size="option.size || 'mini'"
:disabled="option.disabled ? option.disabled(scope.row) : false"
@click.stop="handleOperationClick(option, scope.row, scope.$index)"
>
{{ option.label }}
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination" v-if="pagination">
<el-pagination
:current-page="paginationConfig.currentPage"
:page-size="paginationConfig.pageSize"
:total="paginationConfig.total"
:layout="paginationConfig.layout"
:page-sizes="paginationConfig.pageSizes"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
></el-pagination>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
// 定义 props
const props = defineProps({
// 表格数据
data: {
type: Array,
default: () => []
},
// 列配置
columns: {
type: Array,
default: () => []
},
// 边框
border: {
type: Boolean,
default: true
},
// 斑马纹
stripe: {
type: Boolean,
default: false
},
// 高亮当前行
highlightCurrentRow: {
type: Boolean,
default: false
},
// 行key,用于高亮
rowKey: {
type: String,
default: ''
},
// 最大高度
maxHeight: {
type: [Number, String],
default: ''
},
// 是否显示复选框
selection: {
type: Boolean,
default: false
},
// 是否显示序号
showIndex: {
type: Boolean,
default: false
},
// 序号列标题
indexLabel: {
type: String,
default: '序号'
},
// 序号列宽度
indexWidth: {
type: [Number, String],
default: 80
},
// 操作列配置
operationOptions: {
type: Array,
default: () => []
},
// 操作列标题
operationLabel: {
type: String,
default: '操作'
},
// 操作列宽度
operationWidth: {
type: [Number, String],
default: 180
},
// 分页配置
pagination: {
type: Boolean,
default: false
},
// 分页配置对象
paginationConfig: {
type: Object,
default: () => ({
currentPage: 1,
pageSize: 10,
total: 0,
layout: 'total, sizes, prev, pager, next, jumper',
pageSizes: [10, 20, 30, 50, 100]
})
},
// 行类名函数
rowClassName: {
type: Function,
default: null
}
});
// 定义 emits
const emit = defineEmits([
'selection-change',
'row-click',
'row-dblclick',
'sort-change',
'size-change',
'current-change',
'operation-click'
]);
// 计算分页后的表格数据
const tableData = computed(() => {
if (props.pagination) {
const { currentPage, pageSize } = props.paginationConfig;
return props.data.slice(
(currentPage - 1) * pageSize,
currentPage * pageSize
);
}
return props.data;
});
// 定义方法
const handleSelectionChange = (selection) => {
emit('selection-change', selection);
};
const handleRowClick = (row, column, event) => {
emit('row-click', row, column, event);
};
const handleRowDblclick = (row, column, event) => {
emit('row-dblclick', row, column, event);
};
const handleSortChange = (sort) => {
emit('sort-change', sort);
};
const handleOperationClick = (option, row, index) => {
emit('operation-click', option, row, index);
};
const handleSizeChange = (size) => {
emit('size-change', size);
};
const handleCurrentChange = (page) => {
emit('current-change', page);
};
</script>
<style scoped>
.custom-table {
width: 100%;
}
.pagination {
margin-top: 15px;
display: flex;
justify-content: flex-end;
}
</style>
<template>
<div class="custom-table">
<el-table
:data="tableData"
:border="border"
:stripe="stripe"
:highlight-current-row="highlightCurrentRow"
:row-key="rowKey"
:max-height="maxHeight"
@selection-change="handleSelectionChange"
@row-click="handleRowClick"
@row-dblclick="handleRowDblclick"
@sort-change="handleSortChange"
:row-class-name="rowClassName"
>
<!-- 复选框列 -->
<el-table-column
v-if="selection"
type="selection"
width="55"
></el-table-column>
<!-- 序号列 -->
<el-table-column
v-if="showIndex"
type="index"
:label="indexLabel"
:width="indexWidth"
></el-table-column>
<!-- 自定义列 -->
<el-table-column
v-for="column in columns"
:key="column.prop"
:prop="column.prop"
:label="column.label"
:width="column.width"
:min-width="column.minWidth"
:fixed="column.fixed"
:sortable="column.sortable"
:align="column.align || 'left'"
:show-overflow-tooltip="column.showOverflowTooltip || true"
>
<!-- 插槽支持 -->
<template #default="scope">
<slot
:name="`column-${column.prop}`"
:row="scope.row"
:index="scope.$index"
>
{{ scope.row[column.prop] }}
</slot>
</template>
</el-table-column>
<!-- 操作列 -->
<el-table-column
v-if="operationOptions && operationOptions.length > 0"
:label="operationLabel"
:width="operationWidth"
align="center"
>
<template #default="scope">
<el-button
v-for="option in operationOptions"
:key="option.label"
:type="option.type || 'text'"
:size="option.size || 'mini'"
:disabled="option.disabled ? option.disabled(scope.row) : false"
@click.stop="handleOperationClick(option, scope.row, scope.$index)"
>
{{ option.label }}
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination" v-if="pagination">
<el-pagination
:current-page="paginationConfig.currentPage"
:page-size="paginationConfig.pageSize"
:total="paginationConfig.total"
:layout="paginationConfig.layout"
:page-sizes="paginationConfig.pageSizes"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
></el-pagination>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
// 定义 props
const props = defineProps({
// 表格数据
data: {
type: Array,
default: () => []
},
// 列配置
columns: {
type: Array,
default: () => []
},
// 边框
border: {
type: Boolean,
default: true
},
// 斑马纹
stripe: {
type: Boolean,
default: false
},
// 高亮当前行
highlightCurrentRow: {
type: Boolean,
default: false
},
// 行key,用于高亮
rowKey: {
type: String,
default: ''
},
// 最大高度
maxHeight: {
type: [Number, String],
default: ''
},
// 是否显示复选框
selection: {
type: Boolean,
default: false
},
// 是否显示序号
showIndex: {
type: Boolean,
default: false
},
// 序号列标题
indexLabel: {
type: String,
default: '序号'
},
// 序号列宽度
indexWidth: {
type: [Number, String],
default: 80
},
// 操作列配置
operationOptions: {
type: Array,
default: () => []
},
// 操作列标题
operationLabel: {
type: String,
default: '操作'
},
// 操作列宽度
operationWidth: {
type: [Number, String],
default: 180
},
// 分页配置
pagination: {
type: Boolean,
default: false
},
// 分页配置对象
paginationConfig: {
type: Object,
default: () => ({
currentPage: 1,
pageSize: 10,
total: 0,
layout: 'total, sizes, prev, pager, next, jumper',
pageSizes: [10, 20, 30, 50, 100]
})
},
// 行类名函数
rowClassName: {
type: Function,
default: null
}
});
// 定义 emits
const emit = defineEmits([
'selection-change',
'row-click',
'row-dblclick',
'sort-change',
'size-change',
'current-change',
'operation-click'
]);
// 计算分页后的表格数据
const tableData = computed(() => {
if (props.pagination) {
const { currentPage, pageSize } = props.paginationConfig;
return props.data.slice(
(currentPage - 1) * pageSize,
currentPage * pageSize
);
}
return props.data;
});
// 定义方法
const handleSelectionChange = (selection) => {
emit('selection-change', selection);
};
const handleRowClick = (row, column, event) => {
emit('row-click', row, column, event);
};
const handleRowDblclick = (row, column, event) => {
emit('row-dblclick', row, column, event);
};
const handleSortChange = (sort) => {
emit('sort-change', sort);
};
const handleOperationClick = (option, row, index) => {
emit('operation-click', option, row, index);
};
const handleSizeChange = (size) => {
emit('size-change', size);
};
const handleCurrentChange = (page) => {
emit('current-change', page);
};
</script>
<style scoped>
.custom-table {
width: 100%;
}
.pagination {
margin-top: 15px;
display: flex;
justify-content: flex-end;
}
</style>
页面调用
vue
<template>
<div class="table-demo">
<CustomTable
:data="tableData"
:columns="columns"
border
stripe
highlight-current-row
selection
show-index
:operationOptions="operationOptions"
:pagination="true"
:paginationConfig="paginationConfig"
@selection-change="handleSelectionChange"
@row-click="handleRowClick"
@operation-click="handleOperationClick"
/>
</div>
</template>
<script setup>
import { ref } from 'vue';
import CustomTable from '@/components/CustomTable.vue';
const tableData = ref([
{
id: 1,
name: '张三',
age: 25,
address: '北京市海淀区',
status: '正常',
createTime: '2023-05-01',
updateTime: '2023-05-02'
},
{
id: 2,
name: '李四',
age: 30,
address: '上海市浦东新区',
status: '正常',
createTime: '2023-05-03',
updateTime: '2023-05-04'
},
{
id: 3,
name: '王五',
age: 28,
address: '广州市天河区',
status: '预警',
createTime: '2023-05-05',
updateTime: '2023-05-06'
},
{
id: 4,
name: '赵六',
age: 35,
address: '深圳市南山区',
status: '正常',
createTime: '2023-05-07',
updateTime: '2023-05-08'
},
{
id: 5,
name: '钱七',
age: 22,
address: '杭州市西湖区',
status: '禁用',
createTime: '2023-05-09',
updateTime: '2023-05-10'
}
]);
const columns = ref([
{
prop: 'name',
label: '姓名',
width: '120'
},
{
prop: 'age',
label: '年龄',
width: '80'
},
{
prop: 'address',
label: '地址',
minWidth: '180'
},
{
prop: 'status',
label: '状态',
width: '100',
align: 'center'
},
{
prop: 'createTime',
label: '创建时间',
width: '150',
sortable: true
},
{
prop: 'updateTime',
label: '更新时间',
width: '150'
}
]);
const operationOptions = ref([
{
label: '编辑',
type: 'primary',
size: 'mini',
disabled: (row) => row.status === '禁用'
},
{
label: '删除',
type: 'danger',
size: 'mini'
}
]);
const paginationConfig = ref({
currentPage: 1,
pageSize: 2,
total: tableData.value.length
});
// 事件处理
const handleSelectionChange = (selection) => {
console.log('选择的行:', selection);
};
const handleRowClick = (row, column) => {
console.log('点击行:', row);
};
const handleOperationClick = (option, row) => {
console.log('操作按钮点击:', option.label, row);
};
</script>
<template>
<div class="table-demo">
<CustomTable
:data="tableData"
:columns="columns"
border
stripe
highlight-current-row
selection
show-index
:operationOptions="operationOptions"
:pagination="true"
:paginationConfig="paginationConfig"
@selection-change="handleSelectionChange"
@row-click="handleRowClick"
@operation-click="handleOperationClick"
/>
</div>
</template>
<script setup>
import { ref } from 'vue';
import CustomTable from '@/components/CustomTable.vue';
const tableData = ref([
{
id: 1,
name: '张三',
age: 25,
address: '北京市海淀区',
status: '正常',
createTime: '2023-05-01',
updateTime: '2023-05-02'
},
{
id: 2,
name: '李四',
age: 30,
address: '上海市浦东新区',
status: '正常',
createTime: '2023-05-03',
updateTime: '2023-05-04'
},
{
id: 3,
name: '王五',
age: 28,
address: '广州市天河区',
status: '预警',
createTime: '2023-05-05',
updateTime: '2023-05-06'
},
{
id: 4,
name: '赵六',
age: 35,
address: '深圳市南山区',
status: '正常',
createTime: '2023-05-07',
updateTime: '2023-05-08'
},
{
id: 5,
name: '钱七',
age: 22,
address: '杭州市西湖区',
status: '禁用',
createTime: '2023-05-09',
updateTime: '2023-05-10'
}
]);
const columns = ref([
{
prop: 'name',
label: '姓名',
width: '120'
},
{
prop: 'age',
label: '年龄',
width: '80'
},
{
prop: 'address',
label: '地址',
minWidth: '180'
},
{
prop: 'status',
label: '状态',
width: '100',
align: 'center'
},
{
prop: 'createTime',
label: '创建时间',
width: '150',
sortable: true
},
{
prop: 'updateTime',
label: '更新时间',
width: '150'
}
]);
const operationOptions = ref([
{
label: '编辑',
type: 'primary',
size: 'mini',
disabled: (row) => row.status === '禁用'
},
{
label: '删除',
type: 'danger',
size: 'mini'
}
]);
const paginationConfig = ref({
currentPage: 1,
pageSize: 2,
total: tableData.value.length
});
// 事件处理
const handleSelectionChange = (selection) => {
console.log('选择的行:', selection);
};
const handleRowClick = (row, column) => {
console.log('点击行:', row);
};
const handleOperationClick = (option, row) => {
console.log('操作按钮点击:', option.label, row);
};
</script>