美文网首页js css html
el-table:列表中相同名称的数据实现行合并

el-table:列表中相同名称的数据实现行合并

作者: 橙子只过今天 | 来源:发表于2022-06-29 14:45 被阅读0次

    1. 效果图

    效果图

    2. 页面

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

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

    3. 方法

    handleData: 处理表格数据,将同一名称的数据进行组合
    getSpanArr:获取单元格的合并行数
    objectSpanMethod:合并单元格
    getRowClass:设置表格行的样式类

    /**
     * 处理表格数据,将同一名称的数据进行组合
     */
    const handleData = () => {
      // 排序方法1:将相同名称的数据移动在一起,但会导致所有数据的顺序都被改变
      // state.tableData.sort((a, b) => {
      //   if (a.name != b.name) {
      //     return a.name.localeCompare(b.name) // stringObject.localeCompare(target): 用本地特定的顺序来比较两个字符串
      //   }
      // })
    
      // 排序方法2:只移动有相同名称的数据,保持其它数据的相对顺序不改变
      let keys = [] // 唯一值的数组
      state.tableData.forEach((item, index) => {
        if (!keys.includes(item.moduleName)) {
          keys.push(item.moduleName)
        }
      })
    
      let temp = []
      keys.forEach((item) => {  // 将同一名称的数据放在相邻位置
        state.tableData.forEach((cell) => {
          if (item === cell.name) {
            temp.push(cell)
          }
        })
      })
    
      state.tableData = temp
      getSpanArr(state.tableData)
    }
    
    let spanArr = [] // 每一条数据合并的行数,避免表格错乱!
    /**
     *  获取单元格的合并行数
     * */
    const getSpanArr = (data) => {
      let position  // 当前合并的行位置(连续相同名称的第一条数据位置)
      spanArr = []
      data.forEach((item, index) => {
        if (index === 0) {  // 第一行, 不进行处理
          spanArr.push(1)
          position = 0
        } else {
          if (data[index].name === data[index - 1].name) {
            // 当条数据跟上一条数据名称相同,要合并
            spanArr[position] += 1  // 首条相同名称行合并行数增加
            spanArr.push(0) // 当前行消除
          } else { // 不需要处理的数据
            spanArr.push(1)
            position = index
          }
        }
      })
    }
    
    /** 
     * 合并单元格,此处只合并前三列的属性值 
     * 
    */
    const objectSpanMethod = ({ row, column, rowIndex, columnIndex }) => {
      if (columnIndex < 3) {  // 对前三列进行操作
        const _row = spanArr[rowIndex]  // 合并行数
        const _col = _row > 0 ? 1 : 0 // 合并列数,1:不改变,0:被消除
        return {
          rowspan: _row,
          colspan: _col
        }
      }
    }
    
    /**
     * 设置表格行的样式类(去除合并行内多余的线条)
     */
    const getRowClass = ({ row, rowIndex }) => {
      if (spanArr[rowIndex] > 1) { // 相同名称排列的首行数据
        return 'show-span-row'
      } else if (spanArr[rowIndex] === 0 && spanArr[rowIndex + 1] === 0) {  // 相同名称不处于末尾的被合并数据
        return 'center-span'
      }
    }
    

    4. 样式

    getRowClass设置的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()
        })
    
        /**
         * 处理表格数据,将同一名称的数据进行组合
         */
        const handleData = () => {
          // 排序方法1:将相同名称的数据移动在一起,但会导致所有数据的顺序都被改变
          // state.tableData.sort((a, b) => {
          //   if (a.name != b.name) {
          //     return a.name.localeCompare(b.name) // stringObject.localeCompare(target): 用本地特定的顺序来比较两个字符串
          //   }
          // })
    
          // 排序方法2:只移动有相同名称的数据,保持其它数据的相对顺序不改变
          let keys = [] // 唯一值的数组
          state.tableData.forEach((item, index) => {
            if (!keys.includes(item.moduleName)) {
              keys.push(item.moduleName)
            }
          })
    
          let temp = []
          keys.forEach((item) => {  // 将同一名称的数据放在相邻位置
            state.tableData.forEach((cell) => {
              if (item === cell.name) {
                temp.push(cell)
              }
            })
          })
    
          state.tableData = temp
          getSpanArr(state.tableData)
        }
    
        let spanArr = [] // 每一条数据合并的行数,避免表格错乱!
        /**
         *  获取单元格的合并行数
         * */
        const getSpanArr = (data) => {
          let position  // 当前合并的行位置(连续相同名称的第一条数据位置)
          spanArr = []
          data.forEach((item, index) => {
            if (index === 0) {  // 第一行, 不进行处理
              spanArr.push(1)
              position = 0
            } else {
              if (data[index].name === data[index - 1].name) {
                // 当条数据跟上一条数据名称相同,要合并
                spanArr[position] += 1  // 首条相同名称行合并行数增加
                spanArr.push(0) // 当前行消除
              } else { // 不需要处理的数据
                spanArr.push(1)
                position = index
              }
            }
          })
        }
    
        /** 
         * 合并单元格,此处只合并前三列的属性值 
         * 
        */
        const objectSpanMethod = ({ row, column, rowIndex, columnIndex }) => {
          if (columnIndex < 3) {  // 对前三列进行操作
            const _row = spanArr[rowIndex]  // 合并行数
            const _col = _row > 0 ? 1 : 0 // 合并列数,1:不改变,0:被消除
            return {
              rowspan: _row,
              colspan: _col
            }
          }
        }
    
        /**
         * 设置表格行的样式类(去除合并行内多余的线条)
         */
        const getRowClass = ({ row, rowIndex }) => {
          if (spanArr[rowIndex] > 1) { // 相同名称排列的首行数据
            return 'show-span-row'
          } else if (spanArr[rowIndex] === 0 && spanArr[rowIndex + 1] === 0) {  // 相同名称不处于末尾的被合并数据
            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原理:对每一个单元格返回一个[rowSpan, colSpan]数组, rowSpan表示当前单元格会展示的行数,colSpan表示当前单元格会展示的列数,设置为0时当前单元格被消除。

    参考文章:
    element-ui table :span-method(行合并)
    js将数组中的相同项放在毗邻位置

    相关文章

      网友评论

        本文标题:el-table:列表中相同名称的数据实现行合并

        本文链接:https://www.haomeiwen.com/subject/gpvfbrtx.html