再也不要跟产品说:‘这个功能实现不了了’,记录一下,有需要的可以看看提供各思路。
实现功能:
(1)合并行和合并列
(2)设置指定行的样式
(3)导出删除指定列
(4)导出设置多个sheet
(5)导出指定列宽
像标题所说,可以大致分位两个主要功能点。
第一:用的是饿了么ui里面的表格,el-table的不规则的合并行和列(红框和绿框),并可以设置指定行的样式(蓝色字体)。不多bb,看下图:
说一下实现思路:
1、颜色是用 :row-class-name="" 这个属性
2、表头行合并是用 :header-cell-style=""
3、列的合并是用: :span-method=""
上一下代码吧:
<el-table
class="table"
:data="dataSource"
:border="true"
size='mini'
:cell-style="{ 'text-align': 'center', 'padding':'0px' }"
style="width: 100%"
:row-class-name="tableRowClassName"
:header-cell-style="rowClass"
:span-method="arraySpanMethod"
>
<el-table-column prop="categoryName" label="类别" width="100" :key='tabPosition+"1"'></el-table-column>
<el-table-column prop="childCategoryName" label="类别2" width="100" show-overflow-tooltip :key='tabPosition+"2"'></el-table-column>
<el-table-column prop="contentName" label="工作内容" show-overflow-tooltip :key='tabPosition+"3"'></el-table-column>
<el-table-column prop="resultName" label="成果输出" width="280" show-overflow-tooltip :key='tabPosition+"4"'></el-table-column>
<el-table-column prop="isComplete" label="是否完成" width="100" :key='tabPosition+"5"'>
<template slot-scope="scope">
<span :style="scope.row.isComplete=='是'?'color: #16aa20;':'' ">{{scope.row.isComplete}}</span>
</template>
</el-table-column>
<el-table-column prop="flowStatus" label="流程状态" width="100" :key='tabPosition+"6"'></el-table-column>
<el-table-column label="附件材料" width="100" :key='tabPosition+"7"'>
<template slot-scope="scope">
<el-button type="text" size="small" @click="toDetail(scope.row)">{{isShowSee?scope.row.material:'查看'}}</el-button>
</template>
</el-table-column>
</el-table>
</template>
<script>
// import { queryRecord } from '@/api/index'
export default {
name: "print",
props: {
dataSource:{
type:Array
},
tabPosition:{
type:String
},
// 清单查看进来的都要显示'查看'俩字
isShowSee:{
type:Boolean,
default:true
}
},
data() {
return {
};
},
watch:{
tabPosition(val){
console.log(val)
}
},
created() {
},
methods: {
toDetail(row){
this.$emit('toDetail',row)
},
//合并行
arraySpanMethod({ row, column, rowIndex, columnIndex }) {
// 合并第一列的行 产品名字(categoryId)相同合并
if (columnIndex === 0) {
if(rowIndex ===0 || row.categoryId != this.dataSource[rowIndex-1].categoryId){
let rowspan = 0;
this.dataSource.forEach(element => {
if(element.categoryId === row.categoryId){
rowspan ++;
}
});
return [rowspan, 1];
}else {
return [0, 0];
}
}else if (columnIndex === 1) {
// 合并第二列的行 产品名字(childCategoryId)相同合并
if(rowIndex ===0 || row.childCategoryId != this.dataSource[rowIndex-1].childCategoryId){
let rowspan = 0;
// 从当前index往后找一样的,不是从头找
for(let i=rowIndex;i<this.dataSource.length;i++){
if(this.dataSource[i].childCategoryId === row.childCategoryId){
rowspan ++;
}
}
if(rowIndex !=0){
return [rowspan, 1];
}else{
return [rowspan, 1];
}
}else {
return [0, 0];
}
}else if (columnIndex === 2) {
// 合并第三列的行 产品名字(contentId)相同合并
if(rowIndex ===0 || row.contentId != this.dataSource[rowIndex-1].contentId){
let rowspan = 0;
// 从当前index往后找一样的,不是从头找
for(let i=rowIndex;i<this.dataSource.length;i++){
if(this.dataSource[i].contentId === row.contentId){
rowspan ++;
}
}
if(rowIndex !=0){
return [rowspan, 1];
}else{
return [rowspan, 1];
}
}else {
// 找出下一个和前一个相同的合
return [0, 0];
}
}
},
//合并列 前两列的合并
rowClass({ column,rowIndex,columnIndex}){
if(rowIndex === 0 && columnIndex === 0){
this.$nextTick(() =>{
document.getElementsByClassName(column.id)[0].setAttribute('colSpan',2);
}) // 一定要写在加载完毕后,nextTick 更新的最晚,才能获取到dom节点。
}
if (rowIndex === 0 && columnIndex === 1){
return {display:'none'}
}
return { 'text-align': 'center' }
},
// 颜色
tableRowClassName({row, rowIndex}) {
if(row.hasOwnProperty('isProgress')){
if (row.isProgress==true||row.isProgress=='true') {
return 'success-row';
} else {
return '';
}
return '';
}
}
}
};
</script>
<style lang="scss" scoped>
.table ::v-deep tr.success-row{
color: #2e77ff;
}
</style>
上面是一个组件,在页面中引用:
<div class="main" v-show="tabPosition==navTab[0].id">
<customTable :dataSource="dataSource1" @toDetail="toDetail" ref="exportTableRef" id="file1"/>
</div>
<div class="main" v-show="tabPosition==navTab[1].id">
<customTable :dataSource="dataSource2" @toDetail="toDetail" ref="exportTableRef" id="file2"/>
</div>
<div class="main" v-show="tabPosition==navTab[2].id">
<customTable :dataSource="dataSource3" @toDetail="toDetail" ref="exportTableRef" id="file3"/>
</div>
第二点:表格导出设置列宽和删除列,设置多个sheet页,这里是兼容到IE9吧,先看下效果
这里用到了两个插件:
安装插件
npm install -S file-saver xlsx
npm install -D script-loader
下面是导出的js文件
import FileSaver from "file-saver";
import * as XLSX from 'xlsx'
// import XLSX from 'xlsx'
export function exportPlanTable(tableDom1,tableDom2,tableDom3) {
let tableHeader1 = tableDom1.querySelector('.el-table__header-wrapper');
let tableBody1 = tableDom1.querySelector('.el-table__body');
tableHeader1.childNodes[0].appendChild(tableBody1.childNodes[1]);
let headerDom1 = tableHeader1.childNodes[0].querySelectorAll('th');
// 移除头部
for (let key in headerDom1) {
if (headerDom1[key].innerText === '附件材料') {
if (isIE() || isIE11()) {
headerDom1[key].removeNode(true);
} else {
headerDom1[key].remove();
}
}
if (headerDom1[key].innerText === '类别2') {
if (isIE() || isIE11()) {
headerDom1[key].removeNode(true);
} else {
headerDom1[key].remove();
}
}
}
// 移除附件材料的内容
let tableList1 = tableHeader1.childNodes[0].childNodes[2].querySelectorAll('td');
for (let key = 0; key < tableList1.length; key++) {
if (tableList1[key].innerText === '查看') {
if (isIE() || isIE11()) {
tableList1[key].removeNode(true);
} else {
tableList1[key].remove();
}
}
}
XLSX.utils.table_to_book(tableHeader1)
// let tableDom2 = document.querySelector("#file2").cloneNode(true);
let tableHeader2 = tableDom2.querySelector('.el-table__header-wrapper');
let tableBody2 = tableDom2.querySelector('.el-table__body');
tableHeader2.childNodes[0].appendChild(tableBody2.childNodes[1]);
let headerDom2 = tableHeader2.childNodes[0].querySelectorAll('th');
// 移除头部
for (let key in headerDom2) {
if (headerDom2[key].innerText === '附件材料') {
if (isIE() || isIE11()) {
headerDom2[key].removeNode(true);
} else {
headerDom2[key].remove();
}
}
if (headerDom2[key].innerText === '类别2') {
if (isIE() || isIE11()) {
headerDom2[key].removeNode(true);
} else {
headerDom2[key].remove();
}
}
}
// 移除附件材料的内容
let tableList2 = tableHeader2.childNodes[0].childNodes[2].querySelectorAll('td');
for (let key = 0; key < tableList2.length; key++) {
if (tableList2[key].innerText === '查看') {
if (isIE() || isIE11()) {
tableList2[key].removeNode(true);
} else {
tableList2[key].remove();
}
}
}
XLSX.utils.table_to_book(tableHeader2)
// let tableDom3 = document.querySelector("#file3").cloneNode(true);
let tableHeader3 = tableDom3.querySelector('.el-table__header-wrapper');
let tableBody3 = tableDom3.querySelector('.el-table__body');
tableHeader3.childNodes[0].appendChild(tableBody3.childNodes[1]);
let headerDom3 = tableHeader3.childNodes[0].querySelectorAll('th');
// 移除头部
for (let key in headerDom3) {
if (headerDom3[key].innerText === '附件材料') {
if (isIE() || isIE11()) {
headerDom3[key].removeNode(true);
} else {
headerDom3[key].remove();
}
}
if (headerDom3[key].innerText === '类别2') {
if (isIE() || isIE11()) {
headerDom3[key].removeNode(true);
} else {
headerDom3[key].remove();
}
}
}
// 移除附件材料的内容
let tableList3 = tableHeader3.childNodes[0].childNodes[2].querySelectorAll('td');
for (let key = 0; key < tableList3.length; key++) {
if (tableList3[key].innerText === '查看') {
if (isIE() || isIE11()) {
tableList3[key].removeNode(true);
} else {
tableList3[key].remove();
}
}
}
XLSX.utils.table_to_book(tableHeader3)
var xlsxParam = {
raw: true
}; //转换成excel时,使用原始的格式,这样导出的时候数字过长不会变成科学计数法
let workbook = XLSX.utils.book_new(); //创建一个工作薄
// 这里可以添加多个sheet页
let ws1 = XLSX.utils.table_to_sheet(tableDom1, xlsxParam);
XLSX.utils.book_append_sheet(workbook, ws1, '雏鹰计划'); //将工作表添加到工作簿
let ws2 = XLSX.utils.table_to_sheet(tableDom2, xlsxParam);
XLSX.utils.book_append_sheet(workbook, ws2, '菁鹰计划');
let ws3 = XLSX.utils.table_to_sheet(tableDom3, xlsxParam);
XLSX.utils.book_append_sheet(workbook, ws3, '雄鹰计划');
// 设置列宽
let wscols1 = [
{ wpx : 60 },
{ wpx : 60 },
{ wpx : 440 },
{ wpx : 240 },
{ wpx : 100 },
{ wpx : 100 }
];
ws1["!cols"] = wscols1
ws2["!cols"] = wscols1
ws3["!cols"] = wscols1
let wbout = XLSX.write(workbook, {
bookType: 'xlsx',
bookSST: true,
type: 'array'
});
try {
FileSaver.saveAs(
new Blob([wbout], {
type: 'application/octet-stream;charset=utf-8"'
}), '清单.xlsx');
} catch (e) {
if (typeof console !== 'undefined') console.log(e, wbOut);
}
return wbout;
}
/**
* 判断是否是IE
*/
function isIE() {
if (!!window.ActiveXobject || "ActiveXObject" in window) {
return true;
} else {
return false;
}
}
/**
* 判断是否是IE11
*/
function isIE11(){
if((/Trident\/7\./).test(navigator.userAgent)) {
return true;
} else {
return false;
}
}
页面上引用的时候:
exportTable(){
let tableDom1 = document.querySelector("#file1").cloneNode(true);
let tableDom2 = document.querySelector("#file2").cloneNode(true);
let tableDom3 = document.querySelector("#file3").cloneNode(true);
exportPlanTable(tableDom1,tableDom2,tableDom3)
},
这里没有把删除列的名字和sheet页的名字封装出来,有时间可以自己搞一下啊,仅是提供下思路,优化的地方比较多。