el-table:列表中相同名稱(chēng)的數(shù)據(jù)實(shí)現(xiàn)行合并

1. 效果圖

效果圖

2. 頁(yè)面

使用el-table的span-method屬性控制合并行, 和row-class-name屬性控制行樣式

<el-table
  :data="tableData"
  :height="500"
  :span-method="objectSpanMethod"
  :row-class-name="getRowClass"
>
...省略...
</el-table>

3. 方法

handleData: 處理表格數(shù)據(jù),將同一名稱(chēng)的數(shù)據(jù)進(jìn)行組合
getSpanArr:獲取單元格的合并行數(shù)
objectSpanMethod:合并單元格
getRowClass:設(shè)置表格行的樣式類(lèi)

/**
 * 處理表格數(shù)據(jù),將同一名稱(chēng)的數(shù)據(jù)進(jìn)行組合
 */
const handleData = () => {
  // 排序方法1:將相同名稱(chēng)的數(shù)據(jù)移動(dòng)在一起,但會(huì)導(dǎo)致所有數(shù)據(jù)的順序都被改變
  // state.tableData.sort((a, b) => {
  //   if (a.name != b.name) {
  //     return a.name.localeCompare(b.name) // stringObject.localeCompare(target): 用本地特定的順序來(lái)比較兩個(gè)字符串
  //   }
  // })

  // 排序方法2:只移動(dòng)有相同名稱(chēng)的數(shù)據(jù),保持其它數(shù)據(jù)的相對(duì)順序不改變
  let keys = [] // 唯一值的數(shù)組
  state.tableData.forEach((item, index) => {
    if (!keys.includes(item.moduleName)) {
      keys.push(item.moduleName)
    }
  })

  let temp = []
  keys.forEach((item) => {  // 將同一名稱(chēng)的數(shù)據(jù)放在相鄰位置
    state.tableData.forEach((cell) => {
      if (item === cell.name) {
        temp.push(cell)
      }
    })
  })

  state.tableData = temp
  getSpanArr(state.tableData)
}

let spanArr = [] // 每一條數(shù)據(jù)合并的行數(shù),避免表格錯(cuò)亂!
/**
 *  獲取單元格的合并行數(shù)
 * */
const getSpanArr = (data) => {
  let position  // 當(dāng)前合并的行位置(連續(xù)相同名稱(chēng)的第一條數(shù)據(jù)位置)
  spanArr = []
  data.forEach((item, index) => {
    if (index === 0) {  // 第一行, 不進(jìn)行處理
      spanArr.push(1)
      position = 0
    } else {
      if (data[index].name === data[index - 1].name) {
        // 當(dāng)條數(shù)據(jù)跟上一條數(shù)據(jù)名稱(chēng)相同,要合并
        spanArr[position] += 1  // 首條相同名稱(chēng)行合并行數(shù)增加
        spanArr.push(0) // 當(dāng)前行消除
      } else { // 不需要處理的數(shù)據(jù)
        spanArr.push(1)
        position = index
      }
    }
  })
}

/** 
 * 合并單元格,此處只合并前三列的屬性值 
 * 
*/
const objectSpanMethod = ({ row, column, rowIndex, columnIndex }) => {
  if (columnIndex < 3) {  // 對(duì)前三列進(jìn)行操作
    const _row = spanArr[rowIndex]  // 合并行數(shù)
    const _col = _row > 0 ? 1 : 0 // 合并列數(shù),1:不改變,0:被消除
    return {
      rowspan: _row,
      colspan: _col
    }
  }
}

/**
 * 設(shè)置表格行的樣式類(lèi)(去除合并行內(nèi)多余的線(xiàn)條)
 */
const getRowClass = ({ row, rowIndex }) => {
  if (spanArr[rowIndex] > 1) { // 相同名稱(chēng)排列的首行數(shù)據(jù)
    return 'show-span-row'
  } else if (spanArr[rowIndex] === 0 && spanArr[rowIndex + 1] === 0) {  // 相同名稱(chēng)不處于末尾的被合并數(shù)據(jù)
    return 'center-span'
  }
}

4. 樣式

getRowClass設(shè)置的css樣式

.el-table {
  :deep(tr) {
    &.show-span-row {
      td:nth-of-type(n + 3) {
        border-bottom: none;
      }
    }

    &.center-span {
      td {
        border-bottom: none;
      }
    }
  }
}

5. 整體代碼(Vue3)

<template>
  <el-table
    :data="tableData"
    :height="500"
    :span-method="objectSpanMethod"
    :row-class-name="getRowClass"
  >
  ...省略...
  </el-table>
</template>

<script>
import { reactive, ref, toRefs } from '@vue/reactivity'
import { onMounted, watch } from '@vue/runtime-core'
export default {
  setup(props, context) {

    const state = reactive({
      tableData: []
    })

    onMounted(() => {
      handleData()
    })

    /**
     * 處理表格數(shù)據(jù),將同一名稱(chēng)的數(shù)據(jù)進(jìn)行組合
     */
    const handleData = () => {
      // 排序方法1:將相同名稱(chēng)的數(shù)據(jù)移動(dòng)在一起,但會(huì)導(dǎo)致所有數(shù)據(jù)的順序都被改變
      // state.tableData.sort((a, b) => {
      //   if (a.name != b.name) {
      //     return a.name.localeCompare(b.name) // stringObject.localeCompare(target): 用本地特定的順序來(lái)比較兩個(gè)字符串
      //   }
      // })

      // 排序方法2:只移動(dòng)有相同名稱(chēng)的數(shù)據(jù),保持其它數(shù)據(jù)的相對(duì)順序不改變
      let keys = [] // 唯一值的數(shù)組
      state.tableData.forEach((item, index) => {
        if (!keys.includes(item.moduleName)) {
          keys.push(item.moduleName)
        }
      })

      let temp = []
      keys.forEach((item) => {  // 將同一名稱(chēng)的數(shù)據(jù)放在相鄰位置
        state.tableData.forEach((cell) => {
          if (item === cell.name) {
            temp.push(cell)
          }
        })
      })

      state.tableData = temp
      getSpanArr(state.tableData)
    }

    let spanArr = [] // 每一條數(shù)據(jù)合并的行數(shù),避免表格錯(cuò)亂!
    /**
     *  獲取單元格的合并行數(shù)
     * */
    const getSpanArr = (data) => {
      let position  // 當(dāng)前合并的行位置(連續(xù)相同名稱(chēng)的第一條數(shù)據(jù)位置)
      spanArr = []
      data.forEach((item, index) => {
        if (index === 0) {  // 第一行, 不進(jìn)行處理
          spanArr.push(1)
          position = 0
        } else {
          if (data[index].name === data[index - 1].name) {
            // 當(dāng)條數(shù)據(jù)跟上一條數(shù)據(jù)名稱(chēng)相同,要合并
            spanArr[position] += 1  // 首條相同名稱(chēng)行合并行數(shù)增加
            spanArr.push(0) // 當(dāng)前行消除
          } else { // 不需要處理的數(shù)據(jù)
            spanArr.push(1)
            position = index
          }
        }
      })
    }

    /** 
     * 合并單元格,此處只合并前三列的屬性值 
     * 
    */
    const objectSpanMethod = ({ row, column, rowIndex, columnIndex }) => {
      if (columnIndex < 3) {  // 對(duì)前三列進(jìn)行操作
        const _row = spanArr[rowIndex]  // 合并行數(shù)
        const _col = _row > 0 ? 1 : 0 // 合并列數(shù),1:不改變,0:被消除
        return {
          rowspan: _row,
          colspan: _col
        }
      }
    }

    /**
     * 設(shè)置表格行的樣式類(lèi)(去除合并行內(nèi)多余的線(xiàn)條)
     */
    const getRowClass = ({ row, rowIndex }) => {
      if (spanArr[rowIndex] > 1) { // 相同名稱(chēng)排列的首行數(shù)據(jù)
        return 'show-span-row'
      } else if (spanArr[rowIndex] === 0 && spanArr[rowIndex + 1] === 0) {  // 相同名稱(chēng)不處于末尾的被合并數(shù)據(jù)
        return 'center-span'
      }
    }

    return {
      ...toRefs(state),
      objectSpanMethod
    }
  }
}
</script>

<style lang="scss" scoped>
.el-table {
  :deep(tr) {
    &.show-span-row {
      td:nth-of-type(n + 3) {
        border-bottom: none;
      }
    }

    &.center-span {
      td {
        border-bottom: none;
      }
    }
  }
}
</style>

5. 其它

objectSpanMethod原理:對(duì)每一個(gè)單元格返回一個(gè)[rowSpan, colSpan]數(shù)組, rowSpan表示當(dāng)前單元格會(huì)展示的行數(shù),colSpan表示當(dāng)前單元格會(huì)展示的列數(shù),設(shè)置為0時(shí)當(dāng)前單元格被消除。

參考文章:
element-ui table :span-method(行合并)
js將數(shù)組中的相同項(xiàng)放在毗鄰位置

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容