dynamicTable.vue
<!--多级表头自定义表格 表格组件
使用案例:
<div class="NPcmTableDiv" v-if="cmTableShow" :key="tableKey">
<div v-for="(item,index) in cmTables" :key="index" class="dynTable">
<dynamic-table
:table-data="item.dataList"
:table-header="item.cmTableColumnList"
:height="tableConfig.height"
id="id"
:that="that"
:tabFef="'dynTable'+index"
@selectionChange="selectionChange"
@spanMethod="objectSpanMethod"
></dynamic-table>
<div class="pageDiv" v-if="item.isPaging!='0'" @click="getTableIndex(index)">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="item.pageIndex"
:page-sizes="[10, 20, 30, 40, 50, 100]"
:page-size="item.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="item.dataTotal">
</el-pagination>
</div>
</div>
</div>
-->
<template>
<div class="dynamicTable_container">
<el-table :ref="tabFef" :data="tableData" :height="height" size="mini"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}" :span-method="objectSpanMethod"
@selection-change="handleSelectionChange" row-key="id" @row-click="rowClick" highlight-current-row @current-change="handleCurrentChange">
<template v-for="(item,index) in tableHeader">
<!-- 有子级继续递归 -->
<dynamicColumn
v-if="item.children && item.children.length" :key="index"
:coloumn-header="item" :that="that"
></dynamicColumn>
<!-- 无则直接显示 -->
<template v-else>
<el-table-column v-if="item.cType=='selection' && item.isShow" type="selection" :key="index"
:fixed="item.fixed?item.fixed:false"></el-table-column>
<el-table-column v-else-if="item.cType=='index' && item.isShow" type="index" :key="index"
:label="item.header"
:header-align="item.headerAlign?item.headerAlign:'center'"
:align="item.align?item.align:'center'"
:width="item.width"
:fixed="item.fixed?item.fixed:false"></el-table-column>
<el-table-column v-else-if="item.isShow" :type="item.cType" :key="index"
:label="item.header"
:prop="item.fieldN"
:header-align="item.headerAlign?item.headerAlign:'center'"
:align="item.align?item.align:'center'"
:width="item.width"
:show-overflow-tooltip="true"
:fixed="item.fixed?item.fixed:false"
>
<template slot-scope="scope">
<!-- 特定渲染 renderer不为999 -->
<div v-if="item.renderer&&item.renderer!='999'">
{{renderJs(item.renderer,scope.row[item.fieldN],item.rendererJS)}}</div>
<!-- 自定义渲染 renderer等于999 -->
<XTableReder v-if="item.renderFunc&&item.renderer=='999'" @click.prevent
v-bind="$attrs"
v-on="$listeners"
:sc="scope"
:row="scope.row"
:render="item.render"
:that="that"
></XTableReder>
<!-- 无渲染 -->
<template v-else>
<div>{{scope.row[item.fieldN] | getDictVal(item.data?item.data:'')}}</div>
</template>
</template>
</el-table-column>
</template>
</template>
</el-table>
<el-popover
placement="left" v-model="popVisible"
title=""
width="200"
trigger="hover">
<el-checkbox v-model="item.isShow" v-for="item in tableHeader" :key="item.guid" style="display:block;" @change="changeIsShow">
{{item.cType=='selection'?"多选框":item.header}}
</el-checkbox>
<el-button v-show="isShowColBtn" slot="reference" icon="el-icon-more" circle class="chooseCols" size="mini" ></el-button>
</el-popover>
</div>
</template>
<script>
import renderJs from '../utils/renderJs.js';//封装的日期、金钱等处理数据显示方式的方法
import XTableReder from './XTableReder.vue';//单元格渲染组件
import dynamicColumn from './dynamicColumn.vue';//多级表头动态列组件
export default {
name:"dynamicTable",
props: {
// 表格的数据
tableData: {type: Array},
// 多级表头的数据
tableHeader: {type: Array},
// 表格的高度
height: {
type: [Number,String],
default: 500
},
//筛选多选框选中数据的字段
selKey:{
type: String,
default: 'id'
},
//表格ref
tabFef:{type: String},
//使用组件页面传入的this
that: {},
},
data(){
return{
selection:'',//多选框选中的数据合集
ids:'',//多选框选中的数据合集的id合集
popVisible:false,
chooseColsList:[],
currentRow:null,
isShowColBtn:false,
}
},
components: {
dynamicColumn,XTableReder
},
filters:{
getDictVal(val,data){
if(data && data!=''){
return data[val]
}else{
return val
}
}
},
created(){
//遍历增加显示该列的字段isShow方便控制列的隐藏和显示
this.tableHeader.forEach(item=>{
item.isShow=true
})
window.addEventListener('keydown', this.showColBtn)//监听ctrl+Q
},
methods:{
//日期、金钱等特定方法处理显示数据
renderJs(type,data,text){
renderJs(type,data,text)
},
// 多选框选中数据
handleSelectionChange(selection) {
this.$refs[this.tabFef].setCurrentRow();//清空选择了单行的变色
this.selection='';
this.selection=selection;//多选框选中的数据合集
this.ids = selection.map(item => item[this.selKey]);//从选中数据中,根据传入的字段(如ID)生成只包含该字段的数组,方便调删除接口
this.$emit("selectionChange", this.selection, this.ids);
},
//单行点击事件
rowClick(row){
this.$refs[this.tabFef].toggleRowSelection(row);//选择当前行多选框
this.$refs[this.tabFef].setCurrentRow(row);//单行变色
},
//单行选中事件
handleCurrentChange(val) {
this.currentRow = val;//存储当前行数据
},
//表格合并事件
objectSpanMethod({ row, column, rowIndex, columnIndex }){
return{
rowspan:row.rowspan?row.rowspan[columnIndex]:1,
colspan:row.colspan?row.colspan[columnIndex]:1
}
},
//设置显示的列
changeIsShow(){
this.$refs[this.tabFef].doLayout();
this.$forceUpdate()
},
//ctrl+Q调出表头显示控制按钮
showColBtn(e){
if(e.ctrlKey & e.keyCode == 81){
this.isShowColBtn=!this.isShowColBtn
}
},
},
destroyed(){
window.removeEventListener('keydown', this.showColBtn);
},
}
</script>
<style lang="scss">
.dynamicTable_container{
position: relative;
}
.chooseCols{
position: absolute;
top: 5px;
right: 5px;
}
</style>
dynamicColumn.vue
<!--多级表头自定义表格 列组件-->
<template>
<el-table-column
:label="coloumnHeader.header"
:prop="coloumnHeader.fieldN"
:header-align="coloumnHeader.headerAlign?coloumnHeader.headerAlign:'center'"
:align="coloumnHeader.align?coloumnHeader.align:'center'"
:width="coloumnHeader.width"
:type="coloumnHeader.cType"
:show-overflow-tooltip="true"
:fixed="coloumnHeader.fixed?coloumnHeader.fixed:false">
<template v-for="(item,index) in coloumnHeader.children">
<!-- 有子级继续递归 -->
<tableColumn
v-if="item.children && item.children.length" :key="index"
:coloumn-header="item" :that="that"
></tableColumn>
<!-- 无则直接显示 -->
<template v-else>
<el-table-column v-if="item.cType=='selection'" type="selection" :key="index"
:fixed="item.fixed?item.fixed:false"></el-table-column>
<el-table-column v-else-if="item.cType=='index'" type="index" :key="index"
:label="item.header"
:header-align="item.headerAlign?item.headerAlign:'center'"
:align="item.align?item.align:'center'"
:width="item.width"
:fixed="item.fixed?item.fixed:false"></el-table-column>
<el-table-column v-else
:key="index"
:label="item.header"
:prop="item.fieldN"
:header-align="item.headerAlign?item.headerAlign:'center'"
:align="item.align?item.align:'center'"
:width="item.width"
:type="item.cType"
:show-overflow-tooltip="true"
:fixed="item.fixed?item.fixed:false"
>
<template slot-scope="scope">
<!-- 特定渲染 renderer不为999 -->
<div v-if="item.renderer&&item.renderer!='999'">
{{renderJs(item.renderer,scope.row[item.fieldN],item.rendererJS)}}</div>
<!-- 自定义渲染 renderer等于999 -->
<XTableReder v-if="item.renderFunc&&item.renderer=='999'"
v-bind="$attrs"
v-on="$listeners"
:sc="scope"
:row="scope.row"
:render="item.render"
:that="that"
></XTableReder>
<!-- 无渲染 -->
<template v-else>
<div>{{scope.row[item.fieldN] | getDictVal(item.data?item.data:'')}}</div>
</template>
</template>
</el-table-column>
</template>
</template>
</el-table-column>
</template>
<script>
import renderJs from '../utils/renderJs.js';//封装的日期、金钱等处理数据显示方式的方法
import XTableReder from './XTableReder.vue'//单元格渲染组件
export default {
name: 'tableColumn',
props: {
//传入的父级表头
coloumnHeader: {
type: Object,
required: true
},
//使用组件页面传入的this
that:{}
},
components: {
XTableReder
},
filters:{
getDictVal(val,data){
if(data && data!=''){
return data[val]
}else{
return val
}
}
},
methods:{
//日期、金钱等特定方法处理显示数据
renderJs(type,data,text){
renderJs(type,data,text)
},
}
}
</script>
<style scoped lang="scss">
</style>
XTableReder.vue
<!--多级表头自定义表格 自定义渲染组件-->
<!-- 配置renderFunc案例:
return (h, param,that) => {
const ctl0 = h('el-button', {
//el控件的属性
props:{
value:param.row.xxx,//v-model绑定
size:'mini',
type:'primary',
plain:true,
},
//html原生属性
domProps: {
innerHTML: '编辑',//设置按钮的文字 和输入框冲突使el-input无法显示
},
//样式
style:{
display:(param.row.xxx=='XXX')?'inline-block':'none',//动态显示
},
//控件事件
on: {
change: (value) => {
param.row.xxx=value;//v-model绑定
},
click:()=>{
//阻止冒泡,否则会触发单行点击和多选框勾选
event.stopPropagation();
//click事件的具体代码...
//此处使用that获取使用表格组件的页面的this,不然无法使用页面中的方法数据
}
}
});
return h('div',{
//阻止冒泡,不需要可以去掉
on: {
click:()=>{event.stopPropagation();}
}
},[ctl0]);
}
-->
<script>
export default {
functional: true,
props: {
row: {
type: Object,
required: true,
},
render: {
required: true,
},
sc: {
type: Object,
required: true,
},
rederStyle: {
type: String,
},
that: {},
},
render: (h, ctx) => {
const params = {
row: ctx.props.row,
index: ctx.props.sc.$index,
};
const VNode = ctx.props.render(h, params,ctx.props.that);
return VNode
},
};
</script>