vue3+ant design实现表格相同内容合并为一行

近期在处理数据报表项目过程中频繁面临表格合并的挑战。产品经理希望能将表格中重复内容并合至同一行显示。尽管通过查阅众多博文了解相关方法与实践,但实际操作却无法解决相关问题。例如,提及ant design版本不适配或添加相关代码仍未成功;更为糟糕的是,即使成功合并,数据仍然仅可水平居中,无法实现垂直居中。作为技术支持者,必须满足产品需求,力求保持99%的原型匹配度。虽然工作压力较大,但我坚信这些困难并非无法克服。所以,我也将这些经验分享出来,供大家共同探讨学习。

一、开发页面、获取表格数据

 在使用ant design组件时需要进行提前安转,这个具体安装步骤在ant design官网中有,不会的小伙伴可以去查看一下,但是版本尽量和vue匹配,不然后续在写代码时就会发现有很多都无法使用的问题。安装完组件后就可以正常使用了,下面是具体详细代码:

(1)<template>部分

<template>
  <!-- 表格部分 -->
  <div class="content">
    <div class="table-body">
      <a-table
        :columns="columns"
        :dataSource="tableData"
        :pagination="false"
        bordered
        :scroll="{ y: 'calc(100vh - 520px)' }"
      />
    </div>
    <!-- 分页 -->
    <div class="pagination">
      <a-pagination
        :current="current"
        :size="size"
        :total="pageData.total"
        @change="onChange"
        show-less-items
        show-quick-jumper
        show-size-changer
        :show-total="(total, range) => `共 ${pageData.total || 0} 条`"
      />
    </div>
  </div>
</template>

(2)<script>部分

<script setup>
import { getRoadManageTotal} from '../api/index'
// 分页信息
const pageData = ref({})
// 当前页
const current = ref(1)
// 多少页入参
const size = ref('')
const tableData = ref([])
const columns = ref([
  {
    title: '日期',
    dataIndex: 'tabdate',
    key: 'tabdate',
    align: 'center'
  },
  {
    title: '路线',
    dataIndex: 'tabroad',
    key: 'road',
    align: 'center',
  },
  {
    title: '路段',
    dataIndex: 'tabhighway',
    key: 'highway',
    align: 'center'
  },
  {
    title: '断面流量(万辆)',
    dataIndex: 'tabdmflow',
    key: 'dmflow',
    align: 'center'
  },
  {
    title: '清障统计',
    // dataIndex: 'tabwrecker',
    // key: 'wrecker',
    // align: 'center',
    children: [
      {
        title: '合计(起)',
        dataIndex: 'wreckertotal',
        align: 'center',
        key: 'total',
        width: 100,
        sorter: true
      },
      {
        title: '放空(起)',
        dataIndex: 'wreckvent',
        align: 'center',
        key: 'vent'
      }
    ]
  },
  {
    title: '交通事故(起)',
    dataIndex: 'tabtrafficacci',
    key: 'trafficacci',
    align: 'center'
  }
])

// 获取表格数据
const getTabData = ()=> {
  return new Promise((resolve, reject) => {
    getRoadManageTotal()
      .then(res => {
        tableData.value = []
        if (res.code === 200 && res.data) {
          const dataList = res.data.list
          dataList.forEach((item, index) => {
            console.log(item, 'ieieiei')
            if (item.hj === 'null' && item.fk === 'null' && item.jtsg === 'null') {
              tableData.value.push({
                tabdate: item.createDate,
                tabroad: item.road,
                tabhighway: item.sectionName,
                tabdmflow: item.dmll,
                wreckertotal: 0,
                wreckvent: 0,
                // tabwrecker: item.qzzy,
                tabtrafficacci: 0
              })
            } else {
              tableData.value.push({
                tabdate: item.createDate,
                tabroad: item.road,
                tabhighway: item.sectionName,
                tabdmflow: item.dmll,
                wreckertotal: item.hj,
                wreckvent: item.fk,
                // tabwrecker: item.qzzy,
                tabtrafficacci: item.jtsg
              })
            }
          })
          // console.log(res.data, '数据是:')
          pageData.value = {
            ...pageData.value,
            total: res.data.total,
            showTotal: () => `共 ${res.data.total || 0} 条`
            // current: res.data.page.currentPage
          }
        } else {
          tableData.value = []
        }
        resolve(res.data)
      })
      .catch(error => {
        reject(error)
      })
  })
}
onMounted(() => {
  getTabData()
})
</script>

二、合并行

在需要合并行的表格头部添加customCell,并写入以下代码:

customCell: (record, rowIndex, column) => {
      return {
        rowSpan: rowSpanArr.value[rowIndex],
        style: {
          'text-align': 'center', // 单元格文本居中
          'vertical-align': 'middle' // 单元格内容垂直居中
        }
      }
    }

 在操作完以上步骤之后,重新再定义一个合并行的函数,名为getRowspan,具体代码如下:

//合并行
const getRowspan = (dataScroce, filed) => {
  // console.log(dataScroce, 'dataScrocedataScroce')
  console.log(filed, 'filedfiledfiled')
  let spanArr = []
  let position = 0
  dataScroce.forEach((item, index) => {
    if (index === 0) {
      spanArr.push(1)
      // spanArr.splice(2, 0, 1)
      position = 0
    } else {
      //需要合并的地方判断
      if (dataScroce[index][filed] === dataScroce[index - 1][filed]) {
        spanArr[position] += 1
        spanArr.push(0)
        // spanArr.splice(2, 0, 0)
      } else {
        spanArr.push(1)
        position = index
        console.log(position, ' position position')
      }
    }
  })
  return spanArr
}

我这里需要合并的是时期和路线,所以需要再重新定义两个变量,

//定义合并的时期变量
const rowSpanArr = ref([])
const roadSpanArr = ref([])

操作完以上步骤后,对于定义的这些如何使用呢,这里需要将合并的两个字段进行处理,所以我们在获取表格数据的地方进行操作,

 rowSpanArr.value = getRowspan(tableData.value, 'tabdate')
 roadSpanArr.value = getRowspan(tableData.value, 'tabroad')

这样就完成了相应的合并啦。

三、结果展示、完整代码

可能看完以上代码有些小伙伴还是有些迷糊,下面将完整代码分享给大家吧!

<template>
  <!-- 表格部分 -->
  <div class="content">
    <div class="table-body">
      <a-table
        :columns="columns"
        :dataSource="tableData"
        :pagination="false"
        bordered
        :scroll="{ y: 'calc(100vh - 520px)' }"
      />
    </div>
    <!-- 分页 -->
    <div class="pagination">
      <a-pagination
        :current="current"
        :size="size"
        :total="pageData.total"
        @change="onChange"
        show-less-items
        show-quick-jumper
        show-size-changer
        :show-total="(total, range) => `共 ${pageData.total || 0} 条`"
      />
    </div>
  </div>
</template>

<script setup>
import { getRoadManageTotal} from '../api/index'
// 分页信息
const pageData = ref({})
// 当前页
const current = ref(1)
// 多少页入参
const size = ref('')
const tableData = ref([])
//合并行
const getRowspan = (dataScroce, filed) => {
  // console.log(dataScroce, 'dataScrocedataScroce')
  console.log(filed, 'filedfiledfiled')
  let spanArr = []
  let position = 0
  dataScroce.forEach((item, index) => {
    if (index === 0) {
      spanArr.push(1)
      // spanArr.splice(2, 0, 1)
      position = 0
    } else {
      //需要合并的地方判断
      if (dataScroce[index][filed] === dataScroce[index - 1][filed]) {
        spanArr[position] += 1
        spanArr.push(0)
        // spanArr.splice(2, 0, 0)
      } else {
        spanArr.push(1)
        position = index
        console.log(position, ' position position')
      }
    }
  })
  return spanArr
}
//定义合并的时期变量
const rowSpanArr = ref([])
const roadSpanArr = ref([])
const columns = ref([
  {
    title: '日期',
    dataIndex: 'tabdate',
    key: 'tabdate',
    align: 'center',
    customCell: (record, rowIndex, column) => {
      return {
        rowSpan: rowSpanArr.value[rowIndex],
        style: {
          'text-align': 'center', // 单元格文本居中
          'vertical-align': 'middle' // 单元格内容垂直居中
        }
      }
    }
  },
  {
    title: '路线',
    dataIndex: 'tabroad',
    key: 'road',
    align: 'center',
    customCell: (record, rowIndex, column) => {
      return {
        rowSpan: roadSpanArr.value[rowIndex],
        style: {
          'text-align': 'center', // 单元格文本居中
          'vertical-align': 'middle' // 单元格内容垂直居中
        }
      }
    }
  },
  {
    title: '路段',
    dataIndex: 'tabhighway',
    key: 'highway',
    align: 'center'
  },
  {
    title: '断面流量(万辆)',
    dataIndex: 'tabdmflow',
    key: 'dmflow',
    align: 'center'
  },
  {
    title: '清障统计',
    // dataIndex: 'tabwrecker',
    // key: 'wrecker',
    // align: 'center',
    children: [
      {
        title: '合计(起)',
        dataIndex: 'wreckertotal',
        align: 'center',
        key: 'total',
        width: 100,
        sorter: true
      },
      {
        title: '放空(起)',
        dataIndex: 'wreckvent',
        align: 'center',
        key: 'vent'
      }
    ]
  },
  {
    title: '交通事故(起)',
    dataIndex: 'tabtrafficacci',
    key: 'trafficacci',
    align: 'center'
  }
])
// 获取表格数据
const getTabData = () => {
  return new Promise((resolve, reject) => {
    getRoadManageTotal()
      .then(res => {
        tableData.value = []
        if (res.code === 200 && res.data) {
          const dataList = res.data.list
          dataList.forEach((item, index) => {
            console.log(item, 'ieieiei')
            if (item.hj === 'null' && item.fk === 'null' && item.jtsg === 'null') {
              tableData.value.push({
                tabdate: item.createDate,
                tabroad: item.road,
                tabhighway: item.sectionName,
                tabdmflow: item.dmll,
                wreckertotal: 0,
                wreckvent: 0,
                // tabwrecker: item.qzzy,
                tabtrafficacci: 0
              })
            } else {
              tableData.value.push({
                tabdate: item.createDate,
                tabroad: item.road,
                tabhighway: item.sectionName,
                tabdmflow: item.dmll,
                wreckertotal: item.hj,
                wreckvent: item.fk,
                // tabwrecker: item.qzzy,
                tabtrafficacci: item.jtsg
              })
            }
            rowSpanArr.value = getRowspan(tableData.value, 'tabdate')
            roadSpanArr.value = getRowspan(tableData.value, 'tabroad')
          })
          // console.log(res.data, '数据是:')
          pageData.value = {
            ...pageData.value,
            total: res.data.total,
            showTotal: () => `共 ${res.data.total || 0} 条`
            // current: res.data.page.currentPage
          }
        } else {
          tableData.value = []
        }
        resolve(res.data)
      })
      .catch(error => {
        reject(error)
      })
  })
}
onMounted(() => {
  getTabData()
})
</script>

<style lang="less" scoped>
.search-accident {
  width: 100%;
  height: 12%;
  display: flex;
  align-items: center;
  background-color: #fff;
  .accident-date {
    padding: 0 10px 0 30px;
    font-size: 18px;
    // color: #929292;
  }
  .btn-list {
    display: flex;
    align-items: center;
    ::v-deep .ant-btn {
      line-height: 1.4vw;
      height: 2vw;
    }
  }
}
.content {
  width: 100%;
  height: 85%;
  margin-top: 30px;
  background-color: #fff;
  .content-top {
    display: flex;
    justify-content: flex-end;
    padding-top: 30px;
    padding-right: 30px;
    ::v-deep .ant-btn {
      line-height: 1.4vw;
      height: 2vw;
    }
  }
  .table-body {
    // width: 100%;
    height: 70%;
    margin-top: 2%;
    padding: 0 20px;
    box-sizing: border-box;
    background-color: #fff;
  }
  .pagination {
    // width: 100%;
    height: 10%;
    margin-top: 2%;
    background-color: #fff;
    display: flex;
    justify-content: flex-end;
    align-items: center;
    padding-right: 30px;
  }
}
</style>

  • 11
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Ant Design Vue 4.x 中,表格中的单元格合并可以通过配置 `customRender` 和 `customCell` 方法实现。具体步骤如下: 1. 在表格列的配置项中,使用 `customRender` 方法自定义表格内容,并在需要合并单元格的单元格中使用 `customCell` 方法返回一个包含 `rowspan` 和 `colspan` 属性的对象,指定单元格合并数和列数。 ```js <template> <a-table :columns="columns" :data-source="dataSource" /> </template> <script> export default { name: 'MyTable', data() { return { columns: [ { title: '姓名', dataIndex: 'name', customRender: ({ text, record, index }) => { if (index === 0) { // 只在第一行显示姓名 return { children: text, customCell: () => ({ rowspan: 2, colspan: 1 }) } } else { // 其他不显示姓名 return { children: '', customCell: () => ({ rowspan: 0, colspan: 0 }) } } } }, { title: '年龄', dataIndex: 'age' }, { title: '地址', dataIndex: 'address' } ], dataSource: [ { name: '张三', age: 25, address: '北京市海淀区' }, { name: '', age: 30, address: '上海市浦东新区' }, { name: '李四', age: 35, address: '广州市天河区' }, { name: '', age: 40, address: '深圳市南山区' }, ] } } } </script> ``` 在上面的例子中,通过 `customRender` 方法自定义了表格中第一列的内容,并在第一行的单元格中使用 `customCell` 方法返回一个包含 `rowspan: 2` 和 `colspan: 1` 的对象,指定单元格合并数和列数。 2. 在需要合并单元格的单元格中,使用 `customCell` 方法返回一个包含 `rowspan` 和 `colspan` 属性的对象,指定单元格合并数和列数。在其他单元格中,使用 `customCell` 方法返回一个包含 `rowspan: 0` 和 `colspan: 0` 的对象,将这些单元格隐藏起来。 通过上述方法,即可在 Ant Design Vue表格实现单元格合并并自定义合并后的单元格内容

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值