xml
复制代码
<template>
<div class="columns-table">
<div class="columns-table-main">
<!-- 表格 -->
<el-table
ref="tableRef"
row-key="id"
show-overflow-tooltip
tooltip-effect="dark"
:data="tableData"
v-loading="loading"
:element-loading-text="loadingText"
:border="tableBorder"
:height="tableHeight"
:max-height="tableMaxHeight"
:empty-text="emptyText"
:empty-image="emptyImage"
:default-expand-all="defaultExpandAll"
@selection-change="selectionChange"
@sort-change="sortChange"
:header-cell-style="{
'fond-size': '14px',
height: '40px',
'font-weight': 'bold',
color: 'rgba(0,0,0,0.85)',
'background-color': '#F5F5F5',
'text-align': 'center',
}"
:cell-style="{
'text-align': 'center',
height: '40px',
color: 'rgba(0,0,0,0.85)',
}"
>
<!-- 复选框 -->
<el-table-column
v-if="selection"
:reserve-selection="reserveSelection"
type="selection"
width="45"
fixed
align="center"
>
</el-table-column>
<!-- 序号 -->
<el-table-column
v-if="showIndex"
type="index"
label="序号"
width="60"
align="center"
>
<template #default="scope">
<span>{{ (currentPage - 1) * pageSize + scope.$index + 1 }}</span>
</template>
</el-table-column>
<!-- 其他列 -->
<template v-for="(item, index) in columns">
<template v-if="item.type === 'slot'">
<el-table-column
:key="index"
:width="item.width"
:min-width="item.minWidth"
:prop="item.prop"
:label="item.label"
:align="item.align ? item.align : 'left'"
:fixed="item.fixed ? item.fixed : false"
>
<!-- 操作列 -->
<template #default="scope" v-if="item.slotType == 'options'">
<el-button
type="primary"
text
v-for="(btn, ind) in item.buttons"
:key="ind"
:disabled="scope.row[btn.key]"
@click="btn.fn(scope.row)"
>{{ btn.text }}</el-button
>
</template>
<!-- 普通自定义列 -->
<template #default="scope" v-else>
<slot
:name="item.slotType"
:row="scope.row"
:label="item.label"
:index="scope.$index"
:column="scope.column"
/>
</template>
</el-table-column>
</template>
<!--普通表格-->
<template v-else>
<el-table-column
:key="index"
:sortable="item.sortable"
:prop="item.prop"
:label="item.label"
:width="item.width"
:min-width="item.minWidth || '80'"
:align="item.align ? item.align : 'left'"
:fixed="item.fixed ? item.fixed : false"
></el-table-column>
</template>
</template>
</el-table>
</div>
<div class="columns-table-page">
<!-- 分页 -->
<el-pagination
v-if="showPagination"
:total="total"
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="pageSizes"
background
layout="total, sizes, prev, pager, next, jumper"
></el-pagination>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
let loading = defineModel("loading");
const emits = defineEmits(["selection-change", "sort-change"]);
const props = defineProps({
// 分页
total: {
type: Number,
default: 0,
},
pageSizes: {
type: Array,
default: () => [10, 20, 50, 100],
},
// 表格
tableData: {
type: Array,
default: () => [],
},
columns: {
type: Array,
default: () => [],
},
loadingText: {
type: String,
default: () => "正在加载中...",
},
tableBorder: {
type: Boolean,
default: () => true,
},
tableHeight: {
type: String,
default: () => "auto",
},
tableMaxHeight: {
type: String,
default: () => "500px",
},
emptyText: {
type: String,
default: () => "暂无数据",
},
emptyImage: {
type: String,
default: () => "https://img.yzcdn.cn/vant/empty-block.png",
},
showSummary: {
type: Boolean,
default: () => true,
}, // 是否显示合计行
defaultExpandAll: {
type: Boolean,
default: () => false,
},
// 是否显示复选框
selection: {
type: Boolean,
default: () => true,
},
// 分页的时候是否记录选择复选框状态
reserveSelection: {
type: Boolean,
default: () => true,
},
// 是否展示翻页组件
showPagination: {
type: Boolean,
default: () => true,
},
// 是否展示序号
showIndex: {
type: Boolean,
default: () => false,
},
// 默认选中的数据
checkData: {
type: Array,
default: () => [],
},
});
const tableRef = ref(null);
const selectionChange = (info) => {
emits("selection-change", info);
};
const sortChange = (info) => {
emits("sort-change", info);
};
// 外面监听pageSize和currentPage变化,调用查询数据接口。
const pageSize = defineModel("pageSize");
const currentPage = defineModel("currentPage");
onMounted(() => {
// 复选框默认选中行
if (props.checkData.length > 0) {
props.tableData.forEach((item) => {
if (props.checkData.includes(item.id)) {
tableRef.value.toggleRowSelection(item, true);
} else {
tableRef.value.toggleRowSelection(item, false);
}
});
} else {
tableRef.value.clearSelection();
}
});
// 清除选中状态
const clearSelectionFun = () => {
tableRef.value.clearSelection();
};
defineExpose({
clearSelectionFun,
});
</script>
<style lang="scss" scoped>
.columns-table {
display: flex;
flex-direction: column;
.columns-table-main {
margin-bottom: 12px;
}
.columns-table-page {
display: flex;
justify-content: flex-end;
}
}
</style>
ini
复制代码
<template>
<custom-table
v-model:loading="loading"
:tableData="tableData"
:columns="columns"
:showIndex="tableConfig.showIndex"
:selection="tableConfig.selection"
:tableHeight="tableConfig.tableHeight"
v-model:pageSize="pageConfig.pageSize"
v-model:currentPage="pageConfig.currentPage"
:total="pageConfig.total"
:pageSizes="pageConfig.pageSizes"
@sort-change="sortChange"
@selection-change="selectionChange"
>
<!-- 自定义插槽,可以将插槽中的数据传递出来,status插槽名称,info slot中配置的属性 -->
<template v-slot:status="info">
{{ info.row.status ? "成功" : "成功" }}
</template>
</custom-table>
</template>
<script setup>
import CustomTable from "../components/CustomTable.vue";
import { ref, watch, watchEffect, reactive } from "vue";
// 表格相关
// 可以写在hooks里面
const loading = ref(false); // useHooks
const tableConfig = ref({
showIndex: true,
selection: true,
tableHeight: "calc(100vh - 300px)",
});
const tableData = ref([]); // useHooks
const editFun = (row) => {};
const deleteFun = (row) => {};
const columns = ref([
{
label: "姓名",
prop: "name",
sortable: true,
},
{
label: "年龄",
prop: "age",
sortable: true,
},
{
label: "性别",
prop: "sex",
},
{
label: "自定义",
type: "slot",
slotType: "status",
width: 100,
},
{
label: "操作",
type: "slot", // 插槽
slotType: "options", // 自定义内容
width: 160,
buttons: [
{
text: "编辑",
fn: editFun,
},
{
text: "删除",
fn: deleteFun,
},
],
},
]);
const getTableData = () => {
loading.value = true;
setTimeout(() => {
tableData.value = [
{
id: 1,
name: "zxc",
age: 34,
sex: "男",
status: 1,
address: "北京",
},
{
id: 2,
name: "zxc",
age: 34,
sex: "男",
status: 0,
address: "北京",
},
];
loading.value = false;
}, 1000);
};
const sortChange = (info) => {}; // 排序
const selectionChange = (info) => {}; // 选择
// 分页相关
const pageConfig = reactive({
pageSize: 10,
currentPage: 1,
total: 120,
pageSizes: [10, 20, 50, 100],
});
watch(
[() => pageConfig.currentPage, () => pageConfig.pageSize],
([newCurrent, newSize], [oldCurrent, oldSize]) => {
if (newCurrent !== oldCurrent || newSize !== oldSize) {
getTableData();
}
},
{
immediate: true,
}
);
</script>