VUE 封装动态生成表头表格,单元格动态render渲染el控件,控制隐藏显示列

 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>

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值