基于Vue实现具有固定表头、合并单元格的Html表格

前言

本文主要是通过设置`rowspan`和`colspan`属性来实现合并单元格,通过CSS的`position: sticky`属性来实现固定表头。

一、示例代码

(1)/src/views/Example/HtmlTable/index.vue

<template>
  <div class="table-container">
    <table>
      <thead>
        <tr>
          <th
            colspan="2"
            style="width: auto; height: 30px;"
          >
          </th>
          <th
            style="width: auto; height: 30px; background-color: #0bc9d4; color: #fff; font-size: 14px;"
            v-for="(item, index) in teamList"
            :key="index"
          >{{ item.val }}</th>
        </tr>
      </thead>
      <tbody>
        <template v-for="(map, index) in finalList" :key="index">
          <tr>
            <td style="width: auto; height: 200px; background-color: #4bbae9; writing-mode: vertical-rl; letter-spacing: 1px; color: #fff;" :rowspan="quotaList.length" v-if="map.isFirstTD">{{ map.label }}</td>
            <td style="width: auto; background-color: #0bc9d4; color: #fff; font-weight: bold;">{{ map.quota }}</td>
            <td>{{ map.AAA }}</td>
            <td>{{ map.BBB }}</td>
            <td>{{ map.CCC }}</td>
            <td>{{ map.DDD }}</td>
            <td>{{ map.total }}</td>
          </tr>
        </template>
      </tbody>
    </table>
  </div>
</template>

<script>
export default {
  data: () => ({
    // 初始化表格列表
    tableList: {
      '阶段一': {
        AAA: { xxx: 9, yyy: 3, zzz: 2 },
        BBB: { xxx: 4, yyy: 3, zzz: 2 },
        CCC: { xxx: 7, yyy: 3, zzz: 2 },
        DDD: { xxx: 9, yyy: 3, zzz: 2 },
        total: { xxx: 9, yyy: 3, zzz: 2 },
      },
      '阶段二': {
        AAA: { xxx: 9, yyy: 3, zzz: 2 },
        BBB: { xxx: 5, yyy: 3, zzz: 6 },
        CCC: { xxx: 5, yyy: 5, zzz: 2 },
        DDD: { xxx: 5, yyy: 3, zzz: 5 },
        total: { xxx: 9, yyy: 3, zzz: 2 },
      },
      '阶段三': {
        AAA: { xxx: 4, yyy: 3, zzz: 2 },
        BBB: { xxx: 9, yyy: 3, zzz: 2 },
        CCC: { xxx: 4, yyy: 3, zzz: 2 },
        DDD: { xxx: 4, yyy: 3, zzz: 2 },
        total: { xxx: 4, yyy: 3, zzz: 2 },
      },
      '阶段四': {
        AAA: { xxx: 1, yyy: 3, zzz: 2 },
        BBB: { xxx: 3, yyy: 3, zzz: 2 },
        CCC: { xxx: 1, yyy: 3, zzz: 2 },
        DDD: { xxx: 2, yyy: 3, zzz: 2 },
        total: { xxx: 3, yyy: 3, zzz: 2 },
      },
      '阶段五': {
        AAA: { xxx: 8, yyy: 3, zzz: 2 },
        BBB: { xxx: 9, yyy: 3, zzz: 2 },
        CCC: { xxx: 8, yyy: 3, zzz: 2 },
        DDD: { xxx: 8, yyy: 3, zzz: 2 },
        total: { xxx: 8, yyy: 3, zzz: 2 },
      },
      '阶段六': {
        AAA: { xxx: 6, yyy: 3, zzz: 2 },
        BBB: { xxx: 6, yyy: 3, zzz: 2 },
        CCC: { xxx: 6, yyy: 3, zzz: 2 },
        DDD: { xxx: 9, yyy: 3, zzz: 2 },
        total: { xxx: 9, yyy: 3, zzz: 2 },
      },
    },
    // 团队列表
    teamList: [
      { key: 'AAA', val: 'A团队' },
      { key: 'BBB', val: 'B团队' },
      { key: 'CCC', val: 'C团队' },
      { key: 'DDD', val: 'D团队' },
      { key: 'total', val: '汇总' },
    ],
    // 指标列表
    quotaList: [
      { key: 'X指标', val: 'xxx' },
      { key: 'Y指标', val: 'yyy' },
      { key: 'Z指标', val: 'zzz' },
    ],
    // 加工后表格列表
    finalList: [],
  }),
  methods: {
    fn() {
      const list = []
      const targetList = this.tableList
      for (let stageName in targetList) {
        const itemMap = targetList[stageName]

        for (let i = 0; i < this.quotaList.length; i++) {
          const quotaVo = this.quotaList[i]

          const row = {}
          row.quota = quotaVo.key
          for (let teamVo of this.teamList) {
            const teamKey = teamVo.key
            row[teamKey] = itemMap[teamKey][quotaVo.val]
          }

          if (i === 0) {
            row.isFirstTD = true
            row.label = stageName
          } else {
            row.isFirstTD = false
          }
          list.push(row)
        }
      }
      this.finalList = list
      console.log(this.finalList)
    }
  },
  mounted() {
    this.fn()
  }
};
</script>

<style lang="less" scoped>
.table-container {
  position: relative;
  width: 100%;
  height: 500px;
  // background-color: aliceblue;
  overflow: auto;

  table {
    position: relative;
    width: 100%;
    min-width: 500px;
    height: auto;
    border-spacing: 0 0; // 设置表格中相邻单元格的边界之间的距离
    border-collapse: separate; // 设置表格中相邻单元格的边框为合并边框模型

    thead {

      tr {

        th {
          position: sticky;
          top: 0;
          border-top: 0;
          border-bottom: 0;
          border-left: 5px solid #fff;
          border-right: 0;
          text-align: center;
        }

        & :last-child {
          border-right: 5px solid #fff;
        }
      }
    }

    tbody {

      tr {

        td {
          border-top: 5px solid #fff;
          border-bottom: 0;
          border-left: 5px solid #fff;
          border-right: 0;
          box-shadow: 0 0 5px 1px #eee inset;
          text-align: center;
        }

        & :last-child {
          border-right: 5px solid #fff;
        }
      }
    }
  }
}
</style>

二、运行效果

具体来说,我们将表头单元格的position属性设置为sticky,并将top属性设置为 0,这样表头就会固定在顶部。同时,我们还将表头单元格的背景色设置为白色,以便与表格内容区分开来。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,下面是用 Vue 实现动态合并单元格的表格代码示例: ```html <template> <table> <thead> <tr> <th>姓名</th> <th>年龄</th> <th>性别</th> <th>所在城市</th> </tr> </thead> <tbody> <template v-for="(item, index) in tableData"> <tr :key="index"> <template v-if="isFirstCell(index)"> <td :rowspan="getRowSpan(item)">{{ item.name }}</td> </template> <td>{{ item.age }}</td> <td>{{ item.gender }}</td> <td>{{ item.city }}</td> </tr> </template> </tbody> </table> </template> <script> export default { data() { return { tableData: [ { name: '张三', age: 20, gender: '男', city: '北京' }, { name: '李四', age: 25, gender: '女', city: '上海' }, { name: '王五', age: 30, gender: '男', city: '广州' }, { name: '赵六', age: 35, gender: '女', city: '深圳' }, ], mergeRows: [], }; }, methods: { isFirstCell(index) { return index === 0 || this.mergeRows.indexOf(index) === -1; }, getRowSpan(item) { let count = 1; for (let i = this.tableData.indexOf(item) + 1; i < this.tableData.length; i++) { if (item.name === this.tableData[i].name) { count++; this.mergeRows.push(i); } else { break; } } return count; }, }, }; </script> ``` 在这个示例中,我们先定义了一个表格,表头包括姓名、年龄、性别和所在城市四列。接着使用 `v-for` 指令遍历 `tableData` 数组,通过 `isFirstCell` 方法判断是否为每组数据中的第一个单元格,如果是,则使用 `rowspan` 属性来合并单元格。 `getRowSpan` 方法用于获取每个单元格需要横跨的行数,如果当前行的姓名与下一行的姓名相同,则累加计数器 `count`,同时将需要被合并的行的索引添加到 `mergeRows` 数组中,最后返回计数器的值。最后在模板中使用条件渲染来控制单元格的合并。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值