Element实现表格嵌套、多个表格共用一个表头的方法;

一、分析需求

  • 这里先上一张图说明 需求

根据后端返回的数据 (res 是一个数组,它的元素是一个对象,对象里面的ext属性是一个对象,它又包含了,defaultfreepay三个属性,且这三个都是数组格式。):
在这里插入图片描述

  • 渲染出一个这样子的 表格

res数据:

  1. res的每一个元素的直接属性name (即为邮费模板名称,比如成都运费模板),
  2. resext属性下的三个数组 defaultfreepay,每一个数组要大的一行(这一行中,第一列是运送到的地址的名字,这里定义的是area属性,但后端是未给到这个字段的,可自己处理数据添加该字段 ,这里就不细说了。) 这个area属性占据的这一列,在页面的展示效果 应该是多行合并的效果。在这里插入图片描述

二、代码实现:

<template>
    <div class="layout">
      <el-table :data="res" >
        <el-table-column prop="name">
          <template slot-scope="scope">
            <div class="tab_header">
              <span style="font-weight:600;">{{scope.row.name}}</span>
              <div class="operate">
                <span @click="handleEdit(scope.$index, scope.row)">修改</span>
                <span @click="handleDelete(scope.$index, scope.row)">删除</span>
              </div>
            </div>

            <!-- 这里要实现 多个表格共用一个表头,故需做判断,当表格要渲染的数据为default这个数组的时候,才显示表头的label值 -->
            <!-- 注意:当label无值的时候,还是会占用空间,故当前表格在页面上会出现一个代表表头的空行,需要手动更改(重写)Element表格的 thead样式 -->

            <div v-for="item in (scope.row.ext)" :key="item.id">
              <el-table :data="item" border :class="item!==scope.row.ext.default?'tab-thead-style':''"  style="box-sizing: border-box;border-top:none;" :span-method="objectSpanMethod">
                <el-table-column :label="item===scope.row.ext.default?'运送到':''" prop="area"></el-table-column>
                <el-table-column :label="item===scope.row.ext.default?'首重':''" prop="weight"></el-table-column>
                <el-table-column :label="item===scope.row.ext.default?'运费':''"   prop="first_price"></el-table-column>
                <el-table-column :label="item===scope.row.ext.default?'续重':''"  prop="weight_incre"></el-table-column>
                <el-table-column :label="item===scope.row.ext.default?'最终运费':''"  prop="extend_price"></el-table-column>
              </el-table>
            </div>

          </template>
        </el-table-column>
      </el-table>
    </div>
</template>
<script>
export default {
  data () {
    return {
      // res 参考的是后端返回的数据格式,
      res: [
        {
          id: 1,
          dealer_id: 0,
          name: '成都运费模板',
          type: 1,
          ext: {
            default: [{ area: '默认', type: 1, region: '1', weight: '首重d', weight_incre: '续重d', first_price: '运费d', extend_price: '最终运费d' }],
            free: [{ area: 'free', type: 1, region: '1', weight: '首重f', weight_incre: '续重f', first_price: '运费f', extend_price: '最终运费f' }, { area: 'free', type: 1, region: '1', weight: '首重f', weight_incre: '续重f', first_price: '运费f', extend_price: '最终运费f' }],
            pay: [{ area: 'pay', type: 1, region: '1', weight: '首重p', weight_incre: '续重p', first_price: '运费p', extend_price: '最终运费p' }, { area: 'pay', type: 1, region: '1', weight: '首重p', weight_incre: '续重p', first_price: '运费p', extend_price: '最终运费p' }, { area: 'pay', type: 1, region: '1', weight: '首重p', weight_incre: '续重p', first_price: '运费p', extend_price: '最终运费p' }]
          }
        },
        {
          id: 2,
          dealer_id: 0,
          name: '重庆运费模板',
          type: 2,
          ext: {
            default: [{ area: '默认1', type: 1, region: '1', weight: '首重d', weight_incre: '续重d', first_price: '运费d', extend_price: '最终运费d' }],
            free: [{ area: 'free1', type: 1, region: '1', weight: '首重f', weight_incre: '续重f', first_price: '运费f', extend_price: '最终运费f' }, { area: 'free', type: 1, region: '1', weight: '首重f', weight_incre: '续重f', first_price: '运费f', extend_price: '最终运费f' }],
            pay: [{ area: 'pay1', type: 1, region: '1', weight: '首重p', weight_incre: '续重p', first_price: '运费p', extend_price: '最终运费p' }, { area: 'pay', type: 1, region: '1', weight: '首重p', weight_incre: '续重p', first_price: '运费p', extend_price: '最终运费p' }, { area: 'pay', type: 1, region: '1', weight: '首重p', weight_incre: '续重p', first_price: '运费p', extend_price: '最终运费p' }, { area: 'pay1', type: 1, region: '1', weight: '首重p', weight_incre: '续重p', first_price: '运费p', extend_price: '最终运费p' }, { area: 'pay', type: 1, region: '1', weight: '首重p', weight_incre: '续重p', first_price: '运费p', extend_price: '最终运费p' }, { area: 'pay', type: 1, region: '1', weight: '首重p', weight_incre: '续重p', first_price: '运费p', extend_price: '最终运费p' }]
          }
        }

      ]
    }
  },
  methods: {
    handleEdit (index, row) {
      console.log(index, row)
    },
    handleDelete (index, row) {
      console.log(index, row)
    },
    objectSpanMethod ({ row, column, rowIndex, columnIndex }) {
      if (columnIndex === 0) {
        if (rowIndex === 0) {
          let maxLen
          this.res.forEach(val => {
            const arr = [val.ext.default.length, val.ext.free.length, val.ext.pay.length]
            arr.sort((a, b) => a - b)// arr数组  按数字大小从小到大排序
            maxLen = arr.pop()// 取出排序后的数组arr中的最后一个元素
          })
          return {
            // 这个rowspan应该据 ext的default,pay,free的长度不同来定,取最大长度
            rowspan: maxLen,
            colspan: 1
          }
        } else {
          return {
            rowspan: 0,
            colspan: 0
          }
        }
      }
    }
  }
}
</script>
<style lang="scss">
.layout{

  .tab_header{
   color:#333;
   padding:0 5px 0 5px;
   height:45px;
   line-height:45px;
   border:1px solid #eee;display:flex;
   justify-content: space-between;
   background:rgb(233, 225, 225);
  }
  .operate{
    span{
      font-size: 14px;
      margin-right: 20px;
      margin-right:20px;
      color:#409EFF;
      cursor: pointer;
    }
  }
  /* 处理多个表格共用一个表头时,表头处出现多余空行的问题 (label置空后还是占据空间问题) */
  .tab-thead-style{
      thead{
          display: none;
      }
  }

}
</style>


在这里插入图片描述

三、知识点总结:

  • 为什么要采用这种方式解决(渲染)?

    ① . 项目用的UI组件是Element,它的Table表格组件,没有直接处理行的操作。

    ② . el-table,它是通过注入data对象数组,并在el-table-column 中用prop属性来对应对象中的键名来填入数据,从而渲染出渲染表格。其中el-table-column表示一个列,label属性来定义表格的列名,即对象的一个键名代表一列;

    ③ . 没想到更优的解决办法,O(∩_∩)O哈哈~

  • 多个表格共用一个表头时,注意:

    ①. 需做判断,同时注意label的值。

    ②.el-table-column 的属性label无值的时候,还是会占用空间,故当前表格在页面上会出现一个代表表头的空行,需要手动更改(重写)Element表格的 thead样式

  • table表格嵌套的时候,注意:

    ① . ElementTable组件可 自定义列模板,主要是利用它实现表格嵌套部分,通过 Scoped slot 可以获取到 row, column, $indexstore(table 内部的状态管理)的数据,更多用法参考官网

    ②. ElementTable组件可 合并行或列 ,多行或多列共用一个数据时,可以合并行或列;通过给table传入span-method方法可以实现合并行或列,参考上述代码的 **objectSpanMethod**方法(该表格的第一列需要合并多行——合并渲染表格的data数组的长度那么多行) 或者官网。

后期更新

 **`更新:`**

代码实现处,基本思路是对的,但绑定tab-thead-style类以及用三元运算符确定label的地方实属没必要,这里的本质是 是否展示表头的问题,用show-header属性即可实现,之前没细看文档,别像我学习emo。。。 所以现将代码实现更改如下:

  1. 去除了tab-thead-style类名的定义和class的绑定
  2. 去除了label相关的判定
  3. 给table增加了 show-header的属性,true,显示表头,false则不显示表头。
<template>
  <div class="layout">
    <el-table :data="res">
      <el-table-column prop="name">
        <template slot-scope="scope">
          <div class="tab_header">
            <span style="font-weight: 600">{{ scope.row.name }}</span>
            <div class="operate">
              <span @click="handleEdit(scope.$index, scope.row)">修改</span>
              <span @click="handleDelete(scope.$index, scope.row)">删除</span>
            </div>
          </div>

          <!-- 这里要实现 多个表格共用一个表头,故需做判断,当表格要渲染的数据为default这个数组的时候,才显示表头的label值,即显示表头,设置show-header属性为true -->
          <div v-for="item in scope.row.ext" :key="item.id">
            <el-table
              :data="item"
              border
              :class="item !== scope.row.ext.default ? 'tab-thead-style' : ''"
              style="box-sizing: border-box; border-top: none"
              :span-method="objectSpanMethod"
              :show-header="item === scope.row.ext.default"
            >
              <el-table-column label="运送到" prop="area"></el-table-column>
              <el-table-column label="首重" prop="weight"></el-table-column>
              <el-table-column
                label="运费"
                prop="first_price"
              ></el-table-column>
              <el-table-column
                label="续重"
                prop="weight_incre"
              ></el-table-column>
              <el-table-column
                label="最终运费"
                prop="extend_price"
              ></el-table-column>
            </el-table>
          </div>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>
<script>
export default {
  data() {
    return {
      // res 参考的是后端返回的数据格式,
      res: [
        {
          id: 1,
          dealer_id: 0,
          name: '成都运费模板',
          type: 1,
          ext: {
            default: [
              {
                area: '默认',
                type: 1,
                region: '1',
                weight: '首重d',
                weight_incre: '续重d',
                first_price: '运费d',
                extend_price: '最终运费d',
              },
            ],
            free: [
              {
                area: 'free',
                type: 1,
                region: '1',
                weight: '首重f',
                weight_incre: '续重f',
                first_price: '运费f',
                extend_price: '最终运费f',
              },
              {
                area: 'free',
                type: 1,
                region: '1',
                weight: '首重f',
                weight_incre: '续重f',
                first_price: '运费f',
                extend_price: '最终运费f',
              },
            ],
            pay: [
              {
                area: 'pay',
                type: 1,
                region: '1',
                weight: '首重p',
                weight_incre: '续重p',
                first_price: '运费p',
                extend_price: '最终运费p',
              },
              {
                area: 'pay',
                type: 1,
                region: '1',
                weight: '首重p',
                weight_incre: '续重p',
                first_price: '运费p',
                extend_price: '最终运费p',
              },
              {
                area: 'pay',
                type: 1,
                region: '1',
                weight: '首重p',
                weight_incre: '续重p',
                first_price: '运费p',
                extend_price: '最终运费p',
              },
            ],
          },
        },
        {
          id: 2,
          dealer_id: 0,
          name: '重庆运费模板',
          type: 2,
          ext: {
            default: [
              {
                area: '默认1',
                type: 1,
                region: '1',
                weight: '首重d',
                weight_incre: '续重d',
                first_price: '运费d',
                extend_price: '最终运费d',
              },
            ],
            free: [
              {
                area: 'free1',
                type: 1,
                region: '1',
                weight: '首重f',
                weight_incre: '续重f',
                first_price: '运费f',
                extend_price: '最终运费f',
              },
              {
                area: 'free',
                type: 1,
                region: '1',
                weight: '首重f',
                weight_incre: '续重f',
                first_price: '运费f',
                extend_price: '最终运费f',
              },
            ],
            pay: [
              {
                area: 'pay1',
                type: 1,
                region: '1',
                weight: '首重p',
                weight_incre: '续重p',
                first_price: '运费p',
                extend_price: '最终运费p',
              },
              {
                area: 'pay',
                type: 1,
                region: '1',
                weight: '首重p',
                weight_incre: '续重p',
                first_price: '运费p',
                extend_price: '最终运费p',
              },
              {
                area: 'pay',
                type: 1,
                region: '1',
                weight: '首重p',
                weight_incre: '续重p',
                first_price: '运费p',
                extend_price: '最终运费p',
              },
              {
                area: 'pay1',
                type: 1,
                region: '1',
                weight: '首重p',
                weight_incre: '续重p',
                first_price: '运费p',
                extend_price: '最终运费p',
              },
              {
                area: 'pay',
                type: 1,
                region: '1',
                weight: '首重p',
                weight_incre: '续重p',
                first_price: '运费p',
                extend_price: '最终运费p',
              },
              {
                area: 'pay',
                type: 1,
                region: '1',
                weight: '首重p',
                weight_incre: '续重p',
                first_price: '运费p',
                extend_price: '最终运费p',
              },
            ],
          },
        },
      ],
    }
  },
  methods: {
    handleEdit(index, row) {
      console.log(index, row)
    },
    handleDelete(index, row) {
      console.log(index, row)
    },
    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
      if (columnIndex !== 0) return
      if (rowIndex !== 0) {
        return {
          rowspan: 0,
          colspan: 0,
        }
      }

      let maxLen
      this.res.forEach((val) => {
        const arr = [
          val.ext.default.length,
          val.ext.free.length,
          val.ext.pay.length,
        ]
        arr.sort((a, b) => a - b) // arr数组  按数字大小从小到大排序
        maxLen = arr.pop() // 取出排序后的数组arr中的最后一个元素
      })
      return {
        // 这个rowspan应该据 ext的default,pay,free的长度不同来定,取最大长度
        rowspan: maxLen,
        colspan: 1,
      }
    },
  },
}
</script>
<style lang="scss">
.layout {
  .tab_header {
    color: #333;
    padding: 0 5px 0 5px;
    height: 45px;
    line-height: 45px;
    border: 1px solid #eee;
    display: flex;
    justify-content: space-between;
    background: rgb(233, 225, 225);
  }
  .operate {
    span {
      font-size: 14px;
      margin-right: 20px;
      margin-right: 20px;
      color: #409eff;
      cursor: pointer;
    }
  }
}
</style>

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值