需要

1.表头数据不固定
2.表头数据多层级
3.表格跨行跨列
4.表格可编辑
5.编辑反对根本表单框

子组件代码

dynamic-header.vue

<template>  <div>    <el-form size="medium" class="horizontal" inline>      <slot name="search"></slot>    </el-form>    <div class="title" v-if="title">{{title}}</div>    <el-table      v-loading="listLoading"      :data="list"      :stripe="true"      class="flexible"      :border="true"      :span-method="arraySpanMethod"      style="overflow: auto"      :height="height"      ref="table"      width="100%"    >      <template        v-for="(item,index) in tableHeader">        <table-column  v-if="item.children && item.children.length" :key="Math.random()"  :coloumn-header="item"></table-column>        <el-table-column v-else  class-name="custom"                         :width="item.width?item.width:'auto'"                         :fixed="item.fixed"                         :key="Math.random()"                         :label="item.tableHeadName"                         align="center">          <template slot-scope="scope">            <template v-if="item.isEdit">              <el-select                filterable                v-if='(item.htmlType == "select" || item.htmlType == "radio") && item.dictData'                v-model.lazy="scope.row[item.tableFiled]">                <el-option                  v-for="dict in item.dictData"                  :key="dict[item.options.value] || dict.value"                  :label="dict[item.options.label] || dict.label"                  :value="parseInt(dict[item.options.value] || dict.value)"                />              </el-select>              <el-date-picker                v-else-if='item.htmlType == "datetime" && item.queryType != "BETWEEN"' clearable size="small"                v-model.lazy="scope.row[item.tableFiled]"                type="date"                value-format="yyyy-MM-dd">              </el-date-picker>              <el-date-picker                v-else-if='item.htmlType == "datetime" && item.queryType == "BETWEEN"'                v-model.lazy="scope.row[item.tableFiled]"                size="small"                style="width: 240px"                value-format="yyyy-MM-dd"                type="daterange"                range-separator="-"                start-placeholder="开始日期"                end-placeholder="完结日期"              ></el-date-picker>              <el-input-number                v-else-if='item.htmlType == "number"'                v-model.lazy="scope.row[item.tableFiled]"                clearable                size="small"              />              <el-input                v-else                v-model.lazy="scope.row[item.tableFiled]"                clearable                size="small"              />            </template>            <template v-else-if="item.template">              {{getTemplate(item.template,scope)}}            </template>            <template v-else>              <dict-tag v-if="item.dictData" :options="item.dictData" :value="scope.row[item.tableFiled]" />              <tempalte  v-else-if="item.dictDataArray" >                <dict-tag v-for="(it,itIndex) in item.dictDataArray"  v-if="scope.row[it.props] == it.value" :key="itIndex" :options="it.dictData" :value="scope.row[item.tableFiled]" />              </tempalte>              <template v-else>{{scope.row[item.tableFiled]}}</template>            </template>          </template>        </el-table-column>      </template>      <el-table-column v-if="pageParamInfo.oper" label="操作" :key="index" fixed="right" width="150">        <template slot-scope="scope">          <slot name="oper" :scope="scope.row"></slot>        </template>      </el-table-column>    </el-table>    <slot name="tableFooter" :scope="pageParamInfo.req"></slot>  </div></template><script>  import TableColumn from './table-column'  export default {    props: {      pageParamInfo: {        type: Object,        default(){          return {}        }      },      tableHeader: {        type: Array,        default(){          return []        }      },      RowRules: {        type: Array,        default(){          return []        }      },      list: {        type: Object,        default(){          return {}        }      },      title: {        type: String,        default: ""      },      listLoading: {        type: Boolean,        default:  false      },      height: {        type: String,        default: "70vh"      },    },    // pageParamInfo 页面列表参数:url  req等等;    // tableHeader 表头信息    components: {      TableColumn,    },    data() {      return {      }    },    watch: {      tableHeight(val) {        this.height = val      }    },    created() {    },    mounted() {    },    methods: {      getTemplate(template,scope){        return eval(template)      },      arraySpanMethod({ row, column, rowIndex, columnIndex }) {        let returnMap = {          rowspan: 1,          colspan: 1        }        const data = this.RowRules        if (data instanceof Array && data.length > 0) {          data.forEach(item => {            if (item.col === (columnIndex + 1)) {              if (rowIndex % item.row === 0) {                returnMap = {                  rowspan: item.row,                  colspan: 1                }              } else {                returnMap = {                  rowspan: 0,                  colspan: 0                }              }            }          })        }        return returnMap      },      // 列表      getList() {        this.listLoading = true        this.$http.post(this.pageParamInfo.url, this.pageParamInfo.req).then(res => {          this.listLoading = false          // this.list = res.data.list        })      },      // 文件上传中解决      handleExceed(event, file, fileList) {        this.upload.isUploading = true      },      // 文件上传胜利解决      handleSuccess(response, file, fileList) {        this.upload.open = false        this.upload.isUploading = false        this.$refs.upload.clearFiles()        this.$alert(response.message, '导入后果', {          dangerouslyUseHTMLString: true,        })        this.getList()      },      // 重置      reset() {        /* this.listLoading = true         this.$http.post('busprojecttask/findTaskList', this.req).then(res => {           this.listLoading = false            this.getList(this.req.MONTH)         })*/      },      // 批改      save() {        /* this.listLoading = true          this.$http.post('busprojecttask/findTaskList', this.req).then(res => {            this.listLoading = false             this.getList(this.req.MONTH)          })*/      }    }  }</script><style  lang="scss" scoped>  h1{    color: black !important;    text-align: center;    padding: 20px;  }  table{    margin-top: 20px;  }  .tableClass{    ::v-deep .el-table__fixed{      height: 100% !important;   //设置高优先,以笼罩内联款式    }  }</style>

table-column.vue

<template>  <el-table-column :label="coloumnHeader.tableHeadName" :prop="coloumnHeader.tableFiled" align="center">    <template v-for="item in coloumnHeader.children">      <tableColumn v-if="item.children && item.children.length" :key="Math.random()"  :coloumn-header="item"></tableColumn>      <el-table-column :fixed="item.fixed" :width="item.width?item.width:'auto'"  v-else :key="Math.random()"  :label="item.tableHeadName" :prop="item.tableFiled" align="center">        <template slot-scope="scope">          <template v-if="item.isEdit">            <el-select              v-if='(item.htmlType == "select" || item.htmlType == "radio") && item.dictData'              v-model.lazy="scope.row[item.tableFiled]">              <el-option                v-for="dict in item.dictData"                :key="dict.value"                :label="dict.label"                :value="parseInt(dict.value)"              />            </el-select>            <el-date-picker              v-else-if='item.htmlType == "datetime" && item.queryType != "BETWEEN"' clearable size="small"              v-model.lazy="scope.row[item.tableFiled]"              type="date"              value-format="yyyy-MM-dd">            </el-date-picker>            <el-date-picker              v-else-if='item.htmlType == "datetime" && item.queryType == "BETWEEN"'              v-model.lazy="scope.row[item.tableFiled]"              size="small"              style="width: 240px"              value-format="yyyy-MM-dd"              type="daterange"              range-separator="-"              start-placeholder="开始日期"              end-placeholder="完结日期"            ></el-date-picker>            <el-input-number              v-else-if='item.htmlType == "number"'              v-model.lazy="scope.row[item.tableFiled]"              clearable              size="small"            />            <el-input              v-else              v-model.lazy="scope.row[item.tableFiled]"              clearable              size="small"            />          </template>          <template v-else-if="item.template">            {{getTemplate(item.template,scope)}}          </template>          <template v-else>            <dict-tag v-if="item.dictData" :options="item.dictData" :value="scope.row[item.tableFiled]" />            <tempalte  v-else-if="item.dictDataArray" >              <dict-tag v-for="(it,itIndex) in item.dictDataArray"  v-if="scope.row[it.props] == it.value" :key="itIndex" :options="it.dictData" :value="scope.row[item.tableFiled]" />            </tempalte>            <template v-else>{{scope.row[item.tableFiled]}}</template>          </template>        </template>      </el-table-column>    </template>  </el-table-column></template><script>export default {  name: 'TableColumn',  props: {    coloumnHeader: {      type: Object,      required: true    }  }}</script><style scoped></style>

父组件

list为表格数据,tableHeader为表头数据

<template>  <dynamicHeaderEdit            :tableHeader="tableHeader"            :list="list"            ref="table">          </dynamicHeaderEdit></template>