vue+element plus动态表格
·
vue3+element plus多级表头
如果有更好的实现方法欢迎交流。
动态表格
<template>
<slot name="title"></slot>
<el-table :data="tableData" v-bind="attrs" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
<el-table-column type="index" v-if="props.index.show" :label="props.index.label" :align="props.index.align" :index="props.indexFn"></el-table-column>
<el-table-column type="selection" v-if="props.index.show" :align="props.index.align" ></el-table-column>
<!-- 动态生成多级表头 -->
<el-table-column
v-for="column in colData"
:key="column.id"
:label="column.label"
:prop="column.prop"
:width="column.width"
:show-overflow-tooltip="column.tooltip"
:fixed="column.fixed"
:sortable="column.sortable"
:align="column.align">
<template #header>
<slot name="header" :rowData="{label:column.label,unit:column.unit}">{{column.label}}</slot>
</template>
<template #default="scope" v-if="(column.children || []).length > 0">
<!-- 递归生成子表头 -->
<el-table-column
v-for="child in column.children || []"
:key="child.id"
:label="child.label"
:prop="child.prop"
:width="child.width"
:show-overflow-tooltip="child.tooltip"
:fixed="child.fixed"
:sortable="child.sortable"
:align="child.align">
<template #header>
<slot name="header" :rowData="{label:child.label,unit:child.unit}">{{child.label}}</slot>
</template>
<template #default="scope1" v-if="(child.children || []).length > 0">
<!-- 支持更深层级的表头 -->
<el-table-column
v-for="grandChild in child.children || []"
:key="grandChild.id"
:label="grandChild.label"
:prop="grandChild.prop"
:width="grandChild.width"
:show-overflow-tooltip="grandChild.tooltip"
:fixed="grandChild.fixed"
:sortable="grandChild.sortable"
:align="grandChild.align">
<template #header>
<slot name="header" :rowData="{label:grandChild.label,unit:grandChild.unit}">{{grandChild.label}}</slot>
</template>
<template #default="scope">
<div v-if="grandChild.label == '操作'">
<slot name="button" :rowData="scope.row"></slot>
</div>
<div v-else>
<slot name="default" :rowData="scope.row">{{scope.row[grandChild.prop]}}</slot>
</div>
</template>
</el-table-column>
</template>
<template #default="scope" v-else>
<div v-if="child.label == '操作'">
<slot name="button" :rowData="scope.row"></slot>
</div>
<div v-else>
<slot name="default" :rowData="scope.row">{{scope.row[child.prop]}}</slot>
</div>
</template>
</el-table-column>
</template>
<template #default="scope" v-else>
<div v-if="column.label == '操作'">
<slot name="button" :rowData="scope.row"></slot>
</div>
<div v-else>
<slot name="default" :rowData="scope.row">{{scope.row[column.prop]}}</slot>
</div>
</template>
</el-table-column>
</el-table>
</template>
<script setup lang="ts">
import {onMounted, ref, toRef, useAttrs, watch} from "vue";
interface columnInterface{
label:String,
prop:String,
height:Number
}
// 使用useAttrs获取未声明的props
const attrs = toRef(useAttrs());
let props = defineProps<{
data:{
type:Array<Object>,
required: true,
},
column: {
type: Array<columnInterface>,
required: true,
},
index?: {
type:Object,
default: {show:false,label:'序号',align:'center'},
},
selection?: {
type:Object,
default: {show:false,align:'center'},
},
indexFn?:{
type:Function,
default:()=>{}
}
}>()
let tableData = toRef(props.data)
let colData = ref()
watch(() => props.column,(newValue,oldValue)=>{
console.log('newValue',newValue)
colData.value = buildTableColumns(newValue)
},{ deep: true })
onMounted(() => {
})
interface TableColumn {
id: number;
label: string;
prop?: string;
width?: string | number;
align?: 'left' | 'center' | 'right';
children?: TableColumn[];
tooltip?: true|false;
fixed?:'left'|'right';
sortable?:true|false
}
/**
* 将扁平的列配置转换为树形结构
*/
function buildTableColumns(items: TableColumn[]): TableColumn[] {
const map: Record<number, TableColumn> = {};
const tree: TableColumn[] = [];
items.forEach(item => {
map[item.id] = { ...item, children: [] };
});
items.forEach(item => {
if (item.children && item.children.length > 0) {
// 如果有直接定义的children,使用它
map[item.id].children = item.children.map(child => map[child.id] || child);
} else if (item.pid !== undefined && map[item.pid]) {
// 否则根据pid关联到父节点
map[item.pid].children.push(map[item.id]);
} else {
// 没有父节点的作为根节点
tree.push(map[item.id]);
}
});
return tree;
}
</script>
<style scoped>
</style>
调用按钮和测试页面
<template>
<el-dialog v-bind="attr">
<el-tree
ref="treeRef"
style="max-width: 600px"
:props="treeProps"
:data="data"
show-checkbox
node-key="id"
/>
<el-button @click="getCheckedKeys"></el-button>
</el-dialog>
</template>
<script setup lang="ts">
import {ref, useAttrs, watch} from "vue";
import type {TreeInstance, TreeKey} from "element-plus";
let attr = useAttrs()
let data = ref()
let treeProps={
id:Number,
label:'label',
children: 'children',
}
let treeRef = ref<TreeInstance>()
function getCheckedKeys(){
console.log(treeRef.value!.getCheckedKeys(false))
let ids = treeRef.value!.getCheckedKeys(false)
emits('exportColList',ids)
}
interface colDataInterface{
id: number;
label: string;
prop?: string;
width?: string | number;
align?: 'left' | 'center' | 'right';
children?: colDataInterface[];
tooltip?: true|false;
fixed?:'left'|'right';
sortable?:true|false
}
let emits = defineEmits<{ (e: "exportColList", list: TreeKey[]):void}>()
let props = defineProps<{
colData:{
type:Array<colDataInterface>,
}
}>()
/**
* 将扁平的列配置转换为树形结构
*/
function buildTableColumns(items: colDataInterface[]): colDataInterface[] {
const map: Record<number, colDataInterface> = {};
const tree: colDataInterface[] = [];
items.forEach(item => {
map[item.id] = { ...item, children: [] };
});
items.forEach(item => {
if (item.children && item.children.length > 0) {
// 如果有直接定义的children,使用它
map[item.id].children = item.children.map(child => map[child.id] || child);
} else if (item.pid !== undefined && map[item.pid]) {
// 否则根据pid关联到父节点
map[item.pid].children.push(map[item.id]);
} else {
// 没有父节点的作为根节点
tree.push(map[item.id]);
}
});
return tree;
}
watch(()=>props.colData,(newValue,oldValue) => {
let arr = buildTableColumns(newValue)
data.value = arr
},{immediate:true,deep:true})
</script>
<style scoped>
</style>
<!--动态表格-->
<template>
<el-button @click="testButton = true">测试</el-button>
<dynamic-button v-model="testButton" :col-data="originalColumns" @exportColList="getEditList"></dynamic-button>
<table-commonts :column="originalColumnsTemp" size="small" fit border :height="500" :data="tableData"
show-summary :index="{show:true,label:'序号',align:'center'}" style="width: 100%"
:index-fn="(val) => {return (val+1)*2}" :selection="{show:true,align:'center'}"
@selection-change="handleSelectionChange"
>
<template #button="data">
<el-row>
<el-col :span="12">
<el-button @click="test(data)" link type="primary">保存</el-button>
</el-col>
<el-col :span="12">
<el-button link type="primary">删除</el-button>
</el-col>
</el-row>
</template>
<template #header="scope">
<div>{{scope.rowData.label}}</div>
<div>{{scope.rowData.unit}}</div>
</template>
</table-commonts>
</template>
<script setup lang="ts">
import {onMounted, ref} from "vue";
import TableCommonts from "@/common/tableCommonts.vue";
import DynamicButton from "@/components/dynamicButton.vue";
let testButton = ref(false)
let originalColumnsTemp = ref()
function handleSelectionChange(val){
console.log(val)
}
const tableData = ref([
{name:'111'}
])
function test(val){
console.log(val)
}
function getEditList(data){
originalColumnsTemp.value = originalColumns.value.filter(item =>{
return data.includes(item.id)
})
}
// 示例数据 - 多级表头配置
const originalColumns = ref([
{ id: 1, label: '分公司' ,align:'center',unit:'',prop:'name'},
{ id: 2, label: '采油厂' ,align:'center',unit:''},
{ id: 3, label: '站' ,align:'center',unit:''},
{ id: 4, label: '出站' ,align:'center',unit:''},
{ id: 5, label: '出站名称' ,align:'center',unit:'',pid:4},
{ id: 6, label: '达标率' ,align:'center',unit:'',pid:4},
{ id: 7, label: '主要指标达标率' ,align:'center',unit:'',pid:4},
{ id: 8, label: '含油' ,align:'center',unit:'',pid:4},
{ id: 9, label: '悬浮物' ,align:'center',unit:'',pid:4},
{ id: 10, label: '粒径中值' ,align:'center',unit:'',pid:4},
{ id: 10, label: '腐蚀速率' ,align:'center',unit:'',pid:4},
{ id: 11, label: 'SRB' ,align:'center',unit:'',pid:4},
{ id: 12, label: '铁细菌' ,align:'center',unit:'',pid:4},
{ id: 13, label: '腐生菌' ,align:'center',unit:'',pid:4},
{ id: 14, label: '总铁' ,align:'center',unit:'',pid:4},
{ id: 15, label: '含硫' ,align:'center',unit:'',pid:4},
{ id: 16, label: 'CO₂' ,align:'center',unit:'',pid:4},
{ id: 17, label: 'PH值' ,align:'center',unit:'',pid:4},
{ id: 18, label: '操作' ,align:'center',unit:'',pid:4},
]);
onMounted(() => {
originalColumnsTemp.value = originalColumns.value
})
</script>
<style scoped>
</style>
更多推荐

所有评论(0)