乐趣区

关于table:什么都2023年了你居然还不会table表头单元格合并附eltable单行多级表头多个案例

问题形容

本文记录 el-table 表头合并的多种状况,并提出对应解决方案,预计能帮到局部道友

原生 table 知识点温习

  • 咱们晓得:一个简略的 table 表格个别由一个或多个 trthtd标签组成(嵌套)
  • tr标签定义表格行(table-row即为tr
  • th标签定义表头(table-header即为th
  • td标签定义表格单元格

再简单的表格还包含 captioncolcolgrouptheadtfoottbody等标签,这里暂不延长

而合并单元格次要应用的是 colspanrouspan属性,即为可设置 横跨列 横跨行 的值

而合并单元格次要应用的是 colspanrouspan属性,即为可设置 横跨列 横跨行 的值

而合并单元格次要应用的是 colspanrouspan属性,即为可设置 横跨列 横跨行 的值

晓得这两个属性当前,咱们联合一个具体 demo 来看,就很好的了解了

原生表格 demo

假如咱们须要做一个周一到周末的表格,记录一下工作内容,如下效果图:

对应代码是这样的:

<table border="1">
    <tr>
        <th> 工作日 </th>
        <th> 工作日 </th>
        <th> 工作日 </th>
        <th> 工作日 </th>
        <th> 工作日 </th>
        <th> 周末 </th>
        <th> 周末 </th>
    </tr>
    <tr>
        <th> 周一 </th>
        <th> 周二 </th>
        <th> 周三 </th>
        <th> 周四 </th>
        <th> 周五 </th>
        <th> 周六 </th>
        <th> 周日 </th>
    </tr>
    <tr>
        <td> 下班 </td>
        <td> 下班 </td>
        <td> 下班 </td>
        <td> 下班 </td>
        <td> 下班 </td>
        <td> 加班 </td>
        <td> 加班 </td>
    </tr>
</table>

然而,咱们想把五个工作日和两个周末进行合并一下,这样看起来更加优雅一些,如下需要

  • 由图示,咱们晓得第一行的工作日一共有 5 个,咱们 把后 4 个工作日隐去使其隐没,
  • 让第一个工作日横跨 5 个单元格宽度,即横跨 5 列(本来默认都是横跨 1 列)

先隐去后四个工作日单元格

<tr>
    <th> 工作日 </th>
    <th style="display: none;"> 工作日 </th>
    <th style="display: none;"> 工作日 </th>
    <th style="display: none;"> 工作日 </th>
    <th style="display: none;"> 工作日 </th>
    <th> 周末 </th>
    <th> 周末 </th>
</tr>

变成这样的成果了

  • 这样的话,咱们只须要,再让第一个工作日单元格宽度变宽一些,占据五个单元格,这样的话,宽度有了,就把两个周末挤回到原来失常的地位了
  • 那,如何让第一个工作日单元格,占据五个单元格的宽度呢?
  • 或者说,如何让一个单元格横跨 5 列?
  • 很简略:<th colspan="5"> 工作日 </th>即可
  • rowspan同理,不赘述

需要实现效果图:

对应需要实现代码:

<table border="1">
    <tr>
        <th colspan="5"> 工作日 </th>
        <th style="display: none;"> 工作日 </th>
        <th style="display: none;"> 工作日 </th>
        <th style="display: none;"> 工作日 </th>
        <th style="display: none;"> 工作日 </th>
        <th colspan="2"> 周末 </th>
        <th style="display: none;"> 周末 </th>
    </tr>
    <tr>
        <th> 周一 </th>
        <th> 周二 </th>
        <th> 周三 </th>
        <th> 周四 </th>
        <th> 周五 </th>
        <th> 周六 </th>
        <th> 周日 </th>
    </tr>
    <tr>
        <td> 下班 </td>
        <td> 下班 </td>
        <td> 下班 </td>
        <td> 下班 </td>
        <td> 下班 </td>
        <td> 加班 </td>
        <td> 加班 </td>
    </tr>
</table>

所以,通过下面的 demo,咱们能够得出一个论断:

合并单元格法则论断

  • 合并单元格须要 先暗藏相干单元格,再让某个单元格横向或竖向延长宽度或高度
  • 合并单元格须要 先暗藏相干单元格,再让某个单元格横跨列,或竖跨行

最初咱们审查一下 dom 元素,发现还真是这样的

el-table 单层表头合并案例

无论是饿了么 UI 还是 Iview 等相干的 UI 组件库,都是 给原生 table 套壳子封装 的,所以若是须要合并相应单元格,咱们仍旧能够应用上述的思维形式

咱们持续通过案例来看一下,在 UI 组件库中如何操作合并单元格

本文以表头单元格合并举例,若是有表体单元格合并的需要,能够看笔者之前的这篇文章:https://segmentfault.com/a/1190000040927939

案例一

效果图:

代码:

  • header-cell-style函数用于给表头增加款式,其返回的值会被增加到表头对应款式中去
  • 留神函数的形参中的 column.id 为单元格的 class
  • 大家最好打印一下,联合审查 dom 看类名
<template>
  <el-table
    :data="tableData"
    border
    style="width: 600"
    :header-cell-style="headerCellStyle"
  >
    <el-table-column
      prop="name"
      label="姓名、年龄、他乡"
      width="150"
      align="center"
    ></el-table-column>
    <el-table-column
      prop="age"
      label="年龄"
      width="150"
      align="center"
    ></el-table-column>
    <el-table-column
      prop="home"
      label="他乡"
      width="150"
      align="center"
    ></el-table-column>
    <el-table-column
      prop="hobby"
      label="喜好"
      width="150"
      align="center"
    ></el-table-column>
  </el-table>
</template>

<script>
export default {data() {
    return {
      tableData: [
        {
          name: "孙悟空",
          age: 500,
          home: "花果山水帘洞",
          hobby: "大闹天宫",
        },
        {
          name: "猪八戒",
          age: 88,
          home: "高老庄",
          hobby: "吃包子",
        },
        {
          name: "沙和尚",
          age: 1000,
          home: "通天河",
          hobby: "游泳",
        },
        {
          name: "唐僧",
          age: 99999,
          home: "东土大唐",
          hobby: "取西经",
        },
      ],
    };
  },
  methods: {headerCellStyle({ row, column, rowIndex, columnIndex}) {
      // 第一步:设置表头的第 0 列暂不操作,将地 1 列和第 2 列隐去使其隐没
      if ((columnIndex == 1) | (columnIndex == 2)) {return { display: "none"};
      }
      // 第二步,因为 1、2 列没有了,后续列就会贴上来(后续列往左错位问题)if ((rowIndex == 0) & (columnIndex == 0)) {
        // 解决后续列错位问题,就是将隐去的第 1、2 列的地位再补上,通过第 0 列来补
        this.$nextTick(() => {
          // 原来第 0 列只占据一个地位,当初要去占据三个地位。即占据三列,即设置为横向三个单元格
          document.querySelector(`.${column.id}`).setAttribute("colspan", "3");
          // 这里的 column.id 理论是 dom 元素的 class,故用点. 不必井 #,可审查 dom 验证
          // 通过设置原生的 colspan 属性,让原来的第一列只占据一个单元格的表头占据 3 个单元格即可
        });
      }
    },
  },
};
</script>

<style lang="less">
.el-table {
  th {
    font-weight: bold;
    color: #333;
  }
}
</style>

看,基本上一样的用法:先暗藏再设置横跨竖跨单元格

colspan=’number’ 属性,设置单元格能够横跨几列(默认一个单元格横向只占据一列)

案例二

效果图:

代码:

headerCellStyle({row, column, rowIndex, columnIndex}) {
  // 第一步:隐去第 2 列单元格
  if (columnIndex == 2) {return { display: "none"};
  }
  // 第二步,让第 1 列单元格横跨两列(默认单元格只是横跨一列)if ((rowIndex == 0) & (columnIndex == 1)) {this.$nextTick(() => {document.querySelector(`.${column.id}`).setAttribute("colspan", "2");
    });
  }
},

案例三

效果图:

代码:

headerCellStyle({row, column, rowIndex, columnIndex}) {
  // 第一步:隐去第 3 列单元格
  if (columnIndex == 3) {return { display: "none"};
  }
  // 第二步,让第 2 列单元格横跨两列(默认单元格只是横跨一列)if ((rowIndex == 0) & (columnIndex == 2)) {this.$nextTick(() => {document.querySelector(`.${column.id}`).setAttribute("colspan", "2");
    });
  }
},

案例四

效果图:

代码:

headerCellStyle({row, column, rowIndex, columnIndex}) {
  // 第一步:隐去第 1、2、3 列单元格
  let hideColArr = [1, 2, 3];
  if (hideColArr.includes(columnIndex)) {return { display: "none"};
  }
  // 第二步,让第 0 列单元格横跨四列(默认单元格只是横跨一列)if ((rowIndex == 0) & (columnIndex == 0)) {this.$nextTick(() => {document.querySelector(`.${column.id}`).setAttribute("colspan", "4");
    });
  }
},

el-table 多级表头合并案例

  • 多级表头,须要进一步通过 rowIndex 去找到对应的单元格
  • 因为单层表头,表头只有 1 行,rowIndex必定是 0,所以写不写都无所谓
  • 然而多级表头有不少行,所以须要应用 columnIndex,rowIndex 进一步定位单元格
  • 相似于通过 X 轴 Y 轴 的坐标定位到某个单元格地位

案例五

效果图:

代码:

html 部门须要 el-table-column 标签进行嵌套

<template>
  <el-table
    :data="tableData"
    border
    style="width: 600"
    :header-cell-style="headerCellStyle"
  >
    <el-table-column prop="name" label="姓名" width="150" align="center">
      <el-table-column
        prop="name"
        label="三列根底信息"
        width="150"
        align="center"
      ></el-table-column>
    </el-table-column>
    <el-table-column prop="name" label="年龄" width="150" align="center">
      <el-table-column
        prop="age"
        label="年龄"
        width="150"
        align="center"
      ></el-table-column>
    </el-table-column>
    <el-table-column prop="name" label="他乡" width="150" align="center">
      <el-table-column
        prop="home"
        label="他乡"
        width="150"
        align="center"
      ></el-table-column>
    </el-table-column>
    <el-table-column
      prop="hobby"
      label="喜好"
      width="150"
      align="center"
    ></el-table-column>
  </el-table>
</template>

js 局部持续先暗藏再延长相干单元格

headerCellStyle({row, column, rowIndex, columnIndex}) {
  // 把第 1 列第 1 行和第 2 列第 1 行的单元格隐去
  if ((columnIndex == 1) | (columnIndex == 2)) {if (rowIndex == 1) { // 加上 rowIndex 精准定位
      return {display: "none"};
    }
  }
  // 而后让第 0 列第 1 行的单元格横向占据 3 个单元格地位填充刚刚隐去导致的空白
  if ((columnIndex == 0) & (rowIndex == 1)) { // 加上 rowIndex 精准定位
    this.$nextTick(() => {document.querySelector(`.${column.id}`).setAttribute("colspan", "3");
    });
  }
},

案例六

效果图:

代码:

仍旧是嵌套

<template>
  <el-table
    :data="tableData"
    border
    style="width: 600"
    :header-cell-style="headerCellStyle"
  >
    <el-table-column
      prop="name"
      label="根本信息(姓名、年龄、他乡)"
      align="center"
    >
    </el-table-column>
    <el-table-column
      prop="age"
      label="年龄"
      align="center"
    >
    </el-table-column>
    <el-table-column
      prop="home"
      label="他乡"
      align="center"
    >
    </el-table-column>
    <el-table-column prop="kind" label="所属种族" align="center">
    </el-table-column>
    <el-table-column label="重要信息" align="center">
      <el-table-column label="公开重要信息" align="center">
        <el-table-column prop="nickname" label="法号" align="center">
        </el-table-column>
        <el-table-column prop="hobby" label="喜好 & 性情" align="center">
        </el-table-column>
        <el-table-column prop="personality" label="性情" align="center">
        </el-table-column>
      </el-table-column>
      <el-table-column label="窃密重要信息" align="center">
        <el-table-column prop="bornBackground" label="出身背景" align="center">
        </el-table-column>
        <el-table-column prop="skill" label="技能" align="center">
        </el-table-column>
      </el-table-column>
    </el-table-column>
  </el-table>
</template>

<style lang="less">
.el-table {
  th {
    font-weight: bold;
    color: #333;
  }
}
</style>

先找到 dom,再操作 dom

<script>
export default {data() {
    return {
      tableData: [
        {
          name: "孙悟空",
          age: 500,
          home: "花果山水帘洞",
          kind: "monkey",
          nickname: "斗战败佛",
          hobby: "大闹天宫",
          personality: "怯懦坚韧、疾恶如仇",
          bornBackground: "仙石孕育而生",
          skill: "72 变、筋斗云",
        },
        {
          name: "猪八戒",
          age: 88,
          home: "高老庄",
          kind: "pig",
          nickname: "净坛使者",
          hobby: "吃包子",
          personality: "好逸恶劳、贪图女色",
          bornBackground: "天蓬元帅错投猪胎",
          skill: "36 变",
        },
        {
          name: "沙和尚",
          age: 1000,
          home: "通天河",
          kind: "human",
          nickname: "金身罗汉",
          hobby: "游泳",
          personality: "憨厚老实、不辞辛苦",
          bornBackground: "卷帘大将被贬下界",
          skill: "18 变",
        },
        {
          name: "唐僧",
          age: 99999,
          home: "东土大唐",
          kind: "human",
          nickname: "檀功德佛",
          hobby: "取西经",
          personality: "谦恭儒雅、愚善执著",
          bornBackground: "金蝉子转世",
          skill: "念紧箍咒",
        },
      ],
    };
  },
  methods: {headerCellStyle({ row, column, rowIndex, columnIndex}) {
      /**
       * 合并:根本信息(姓名、年龄、他乡)单元格【通过行与列的索引来合并】* */
      let colArr = [1, 2];
      if (colArr.includes(columnIndex)) {if (rowIndex == 0) {
          // 把第 1 列第 0 行和第 2 列第 0 行的单元格隐去
          return {display: "none"};
        }
      }
      if ((columnIndex == 0) & (rowIndex == 0)) {
        // 把第 0 列第 0 行的单元格横向延长,补上刚刚隐去的单元格地位,并上个色
        this.$nextTick(() => {document.querySelector(`.${column.id}`).setAttribute("colspan", "3");
        });
        return {background: "pink"};
      }
      /**
       * 合并:重要信息 ---> 公开重要信息 ---> 喜好性情单元格【通过单元格的文字内容来合并】* */
      if (column.label == "性情") {return { display: "none"};
      }
      if (column.label == "喜好 & 性情") {this.$nextTick(() => {document.querySelector(`.${column.id}`).setAttribute("colspan", "2");
        });
        return {background: "orange"}; // 不加这个也行,加了只是为了更好辨别
      }

      /**
       * 重要!重要!重要!*    咱们想要合并表头的单元格,须要先找到对应单元格
       *    能够通过列 column 对象的 label 或者行与列索引来找到,找到当前进行暗藏或合并
       *    也能够遍历行 row 数组找,不过会麻烦一些,集体倡议通过 column 来找
       * */
      // 通过 column 找
      if (column.label == "技能") {return { background: "#baf"};
      }
      // 通过 row 找
      for (const item of row) {if (item.label == "重要信息") {this.$nextTick(() => {document.querySelector(`.${item.id}`).style.background = "#ea66a6";
          });
          break;
        }
      }
    },
  },
};
</script>
  • 还能够,间接通过 column.label 找到对应单元格,而后进行合并单元格操作,不应用 rowIndex 和 columnIndex 了
  • 这种形式,在某些状况下,会更加不便
  • 但无论哪种形式,实质思路都是先找到单元格,再进行合并相干操作
headerCellStyle({row, column, rowIndex, columnIndex}) {
  // 第一局部的合并
  if (column.label == "年龄") {return { display: "none"};
  }
  if (column.label == "他乡") {return { display: "none"};
  }
  if (column.label == "根本信息(姓名、年龄、他乡)") {this.$nextTick(() => {document.querySelector(`.${column.id}`).setAttribute("colspan", "3");
    });
    return {background: "pink"};
  }
  // 第二局部的合并
  if (column.label == "性情") {return { display: "none"};
  }
  if (column.label == "喜好 & 性情") {this.$nextTick(() => {document.querySelector(`.${column.id}`).setAttribute("colspan", "2");
    });
    return {background: "orange"};
  }
},

总结

读到这里,大家对表头合并相干问题应该都能应答了,若是还有不能应答的,能够发到评论区,大家一块帮忙解决

A good memory is better than a bad pen. Write it down…

退出移动版