vue+element 多级嵌套表头解决方案

5,596 阅读1分钟

开发中碰到了一个复杂的表格,多级表头嵌套,可编辑,动态传入操作按钮,没找到合适的插件,就自己开发了一个 效果截图如下

微信图片_20210819151250.png

原型图截图如下,算是100%还原原型图了(部分敏感信息已马赛克,保密,我们是专业的)

image.png

先看组件部分

index.vue

<template>
  <div >
    <el-table
      ref="tab"
      :show-summary="isShowSum"
      :data="tableData"
      :height="height"
      @selection-change="handleSelectionChange"
      style="width: 100%"
    >
    <el-table-column
            v-if="isShowBox"
            type="selection"
            width="55"/>
      <template>
        <column-item
          v-for="item in col"
          :key="item.label"
          :col="item"
          v-on="$listeners"
        />
      </template>
      <template
        v-if="operates"
      >
        <el-table-column
          ref="fixedColumn"
          :width="operates.width"
          :fixed="operates.fixed"
          label="操作"
          :align="operates.align"
        >
          <template slot-scope="scope">
           
            <div class="operate-group">
              <template v-for="(btn, leftOpkey) in operates.list">
                  <el-button
                    :type="btn.type"
                    size="small"
                    :code="btn.code"
                    @click="btn.method(scope.$index, scope.row, $event)"
                  >{{ btn.title }}</el-button>
              </template>
            </div>
          </template>
        </el-table-column>
      </template>
       <template #empty>
        <div class="empty" 
             style="height: 200px">
          <span class="empty-desc">暂无数据</span>
        </div>
      </template>

    </el-table>
  </div>
</template>
<script>
import ColumnItem from "./column";
export default {
  name: "TableItem",
  components: {
    ColumnItem,
  },
  props: {
    operates: {
      type: Object,
      default: () => {
        return {}
      } 
    },
    //表格数据
    tableData: {
      type: Array,
      default: () => [],
    },
    //表头数据
    col: {
      type: Array,
      default: () => [],
    },
    //是否在表格下方显示合计
    isShowSum: {
      type: Boolean,
      default: false,
    },
    //判断单元格文字是居中还是左对齐显示,默认居中
    alignType: {
      type: String,
      default: "center",
    },
    //设置表格高度,固定表头
    height: {
      type: String,
      default: null, //默认不固定表头
    },
    //判断是否显示多选框
    isShowBox: {
      type: Boolean,
      default: false, //默认不展示
    },
  },
  data() {
    return {
     
    };
  },
  created() {},
  mounted() {
  },
  methods: {
      handleSelectionChange(row){
          console.log(row)
      }
  },
};
</script>
<style>

/* 处理表格表头和内容错位问题 */
.el-table th.gutter {
  display: table-cell !important;
}
.el-table th,
.el-table td {
  padding: 7px 0 !important;
}
</style>
column.vue
<template>
  <el-table-column
    :prop="col.field"
    :label="col.title"
    :align="alignType"
    :fixed="col.fixed"
    :width="col.width || ''"
  >
    <template v-for="(item, index) of col.children">
      <!--这么写再来多少级嵌套都不怕了-->
      <column-item v-if="item.children" 
                   :key="index" :col="item" v-on="$listeners" />
      <el-table-column
        v-else-if="item.inputType == 'edit'"
        :label="item.title"
        :key="index + item.field"
        :width="col.width || ''"
      >
        <template slot-scope="scope">
          <el-input
            v-model="scope.row[item.field]"
            @change="changeAmount(scope.row, item.field)"
          >
            <i slot="suffix" 
               class="el-icon-edit el-input__icon" />
          </el-input>
        </template>
      </el-table-column>

      <el-table-column
        v-else
        :key="index"
        :label="item.title"
        :prop="item.field"
        :align="alignType"
        :width="col.width || ''"
      />
    </template>
  </el-table-column>
</template>

<script>
export default {
  name: "ColumnItem",
  props: {
    col: {
      type: Object,
      default: () => [],
    },
    //判断单元格文字是居中还是左对齐显示
    alignType: {
      type: String,
      default: "left", //默认居中
    },
  },
  methods: {
    async changeAmount(row) {
      this.$emit('postArr',row)
    },
  },
};
</script>
表头数据示例
export const column1 = [
    {
        id: 1,
        title: '销售任务',
        field: 'data1',
        width: 0,
        inputType: 'read'
    }, {
        id: 2,
        title: '月销售额',
        field: 'data2',
        width: 0,
        inputType: 'read',
        children: [
            {
                id: 3,
                title: '1月销售额',
                field: 'sales1',
                width: 0,
                inputType: 'read',
            },
            {
                id: 4,
                title: '2月销售额',
                field: 'sales2',
                width: 0,
                inputType: 'read',
            },
            {
                id: 5,
                title: '3月销售额',
                field: 'sales3',
                width: 0,
                inputType: 'read',
            }
        ]
    },
    {
        id: 7,
        title: '增长率',
        field: '',
        width: 0,
        inputType: 'read',
        children: [
            {
                id: 8,
                title: '1季度',
                field: '',
                width: 0,
                inputType: 'read',
                children: [
                    {
                        id: 9,
                        title: '1月',
                        field: 'month1SalesGrowthRatio',
                        width: 0,
                        inputType: 'read',
                    },
                    {
                        id: 10,
                        title: '2月',
                        field: 'month2SalesGrowthRatio',
                        width: 0,
                        inputType: 'read',
                    },
                    {
                        id: 11,
                        title: '3月',
                        field: 'month3SalesGrowthRatio',
                        width: 0,
                        inputType: 'read',
                    }
                ]
            }
        ]
    },
    {
        id: 12,
        title: '销售目标预测',
        field: '',
        width: 0,
        inputType: 'read',
        children:[
            {
                id: 13,
                title: '1月',
                field: 'predictMonth1',
                width: 0,
                inputType: 'edit',
            },
        ]
    }
]
页面应用(数据都是随便写的)
<template>
  <div>
    <h3>多表头嵌套,内容可编辑</h3>
    <tableTree :col="column1" :table-data="tableData" :operates="operates" @postArr="postArr" />
  </div>
</template>
<script>
import tableTree from "@/components/table-tree";
import { column1 } from "./js/table-column";

export default {
  components: { tableTree },
  data() {
    return {
      column1,
      //如果后台返回的是二维数组需要自己转化下哦
      tableData: [
        {
          data1: "100000",
          sales1: "566",
          sales2: "236",
          sales3: "522",
          month1SalesGrowthRatio: "0%",
          month2SalesGrowthRatio: "30%",
          month3SalesGrowthRatio: "20%",
          predictMonth1: "800",
        },
        {
          data1: "200000",
          sales1: "23",//这销售额老板会打人的吧
          sales2: "45",
          sales3: "565",
          month1SalesGrowthRatio: "30%",
          month2SalesGrowthRatio: "30%",
          month3SalesGrowthRatio: "50%",
          predictMonth1: "800",
        },
      ],
      operates: {
        width: 150,
        fixed: "right",
        list: [
          {
            title: "编辑",
            type:'text',
            method: (index, row) => {
              this.editRole(row);
            },
            code: "ui",
          },
          {
            title: "删除",
            type:'primary',
            method: (index, row) => {
              this.deleteRole(row);
            },
            code: "ui",
          },
        ],
      },
    };
  },
  methods: {
    postArr(row) {
      this.$message({
        type: "success",
        message: "修改成功!",
      });
    },
    deleteRole(row){
      this.$message({
        type: "success",
        message: "删除成功!",
      });
    },
    editRole(row){
      this.$message({
        type: "success",
        message: "编辑成功!",
      });
    }
  },
};
</script>
<style scoped>
h3 {
  text-align: left;
}
</style>

拿走不谢~