先上效果:
1.自定义表头:
通过设置 slot="header" 来自定义表头。 slot-scope="scope" 这一行千万不要因为没有再template中使用到scope,vscode报红而删除,这会导致input框不能输入任何内容!
<template slot="header" slot-scope="scope">//slot-scope="scope" 千万不要因为vscode报红删除
<el-row :gutter="2">
<el-col :span="12">
<el-form-item
:label="`病案号${caseIndex + 1}:`"
:prop="`data.${0}.patientList.${caseIndex}.bah`"
:rules="tableRuleForm.bah"
>
<el-select
v-model="caseItem.bah"
value-key="brid"
placeholder="请输入关键词并回车"
>
<el-option
v-for="item in medicalOptions"
:key="item.brid"
:label="item.bah"
:value="item"
>
<span>{{ item.brxm }}:{{ item.bah }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="病人姓名:"
:prop="`data.${0}.patientList.${caseIndex}.brxm`"
:rules="tableRuleForm.brxm"
>
<el-input
@change="$forceUpdate()"
v-model="caseItem.brxm"
size="mini"
placeholder="请输入病人姓名"
/>
</el-form-item>
</el-col>
</el-row>
</template>
2.多级表头和表头合并:
在 el-table-column 里面嵌套 el-table-column就可以实现多级表头。
<el-table-column
prop="amount1"
v-for="(caseItem, caseIndex) in tableData.data[0].patientList"
:key="caseIndex"
>
<el-table-column prop="amount1" label="完全符合">
<el-table-column prop="amount1" align="center" width="80">
</el-table-column>
</el-table-column>
<el-table-column prop="amount1" label="部分符合"
><el-table-column prop="amount1" align="center" width="80">
</el-table-column>
</el-table-column>
</el-table-column>
因为下边还有要操作的单元格,所以总符合率这里必须要将三列合并为一列。所以我们要找到需要合并的单元格位置,使用 .colSpan 属性来合并单元格,这里循环是因为table的列是动态添加的所以进行循环合并,如果是固定的列,就不需要循环,直接找到要合并的列就行了。setColSpan方法一定要等table的dom全部渲染完成了才可以调用!否则获取不到节点。我这里是放在mounted()函数中并设置了一个setTimeout用了300毫秒的延时调用。
// 合并表头
setColSpan() {
// 获取第三行的多级表头
let row = document
.getElementsByClassName("is-group")[0]
.getElementsByTagName("tr")[2];
// console.log(row); //这里获取的表头排除了序号,检查项目,检查内容
// 获取每一列
let colAll = row.getElementsByTagName("th");
// 循环列, .length -3 是减去序号,检查项目,检查内容这三列
for (let index = 0; index < colAll.length - 3; index++) {
if (index % 6 == 0) {
// 只要当前列模以6是0就将本列加3(找到 不适用 下的这一列)的单元格的colSpan设为3
row.getElementsByTagName("th")[index + 3].colSpan = 3;
// 把接下来的两行设置为none 防止挤后边的
row.getElementsByTagName("th")[index + 4].style.display = "none";
row.getElementsByTagName("th")[index + 5].style.display = "none";
}
}
},
3.行内容一致的跨行合并:
通过给
table
传入span-method
方法可以实现合并行或列,方法的参数是一个对象,里面包含当前行row
、当前列column
、当前行号rowIndex
、当前列号columnIndex
四个属性。该函数可以返回一个包含两个元素的数组,第一个元素代表rowspan
,第二个元素代表colspan
。 也可以返回一个键名为rowspan
和colspan
的对象。
<el-table
:data="tableData.data"
:span-method="objectSpanMethod"
border
height="calc(100vh - 280px)"
style="width: 100%"
class="table"
>
</el-table>
下边是方法
// 合并行
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
const dataProvider = this.tableData.data;
if (columnIndex === 1) {
const prevRow = dataProvider[rowIndex - 1]; //上一条数据
let nextRow = dataProvider[rowIndex + 1]; //下一条数据
// 如果上一条数据存在并且上一条数据和当前数据相同,那么就不渲染这个单元格
if (prevRow && prevRow.BZMC === row.BZMC) {
return { rowspan: 0, colspan: 0 };
//不相同判断如何渲染
} else {
let rowspan = 1;
// 如果下一条数据和当前数据相同那么应该合并单元格 while判断下边有几行和当前数据相同,while直到找到不相同的退出循环
while (nextRow && nextRow.BZMC === row.BZMC) {
rowspan++;
// 只要当前行和下一行相同,那么对比rowspan加下一条数据是否相同
nextRow = dataProvider[rowspan + rowIndex];
}
if (rowspan > 1) {
return { rowspan, colspan: 1 };
}
}
}
},
这里用while循环来判断到底进行多少次跨行合并。
4.table动态新增列的时候表格中间出现一大片空白,样式错乱
因为我这个table的列是动态新增的,在病案历数select框中我多选择一例就会新增病案号,病人姓名这几列。所以病案号是一个数组循环出来的列,我新增的时候push进去一个病人信息对象,table重新被渲染。渲染的时候table会闪一下然后出现一大片空白,如图:
具体原因不知道为什么,但是我猜测是因为我直接对渲染的table :data="tableData" 进行了操作导致的,所以我的解决方法是先拷贝一份当前渲染的tableData,操作拷贝的这个对象,最后先将tableData赋空,再把拷贝的对象赋值给tableData,这样就完美解决了。
changeCaseNum(value) {
//深拷贝一份当前正在渲染的tableData进行操作
let data = JSON.parse(JSON.stringify(this.tableData.data));
if (data[0].patientList.length < value) {
while (data[0].patientList.length < value) {
data.forEach((item) => {
item.patientList.push({
fz: "100.00",
bah: "",
brxm: "",
df: "0",
wqfhs: data.length,
bffhs: 0,
bfhs: 0,
});
});
}
} else {
data.forEach((item) => {
item.patientList.splice(value);
});
}
//先将当前渲染的talbeData 赋空
this.tableData.data = [];
//然后再将拷贝的data赋值给el-talbe渲染
setTimeout(() => {
this.tableData.data = data;
});
// 重新调用合并表头的方法
setTimeout(() => {
this.setColSpan();
}, 300);
},
记得操作完table之后要重新调用 setColSpan()进行表头合并。