热搜:fiddler git ip ios 代理
历史搜索

vue el

游客2024-08-18 09:30:01
目录文章目录
  1. 产品需求
  2. 关键代码
  3. 如何使用
  4. 结语

最近,项目上遇到了复杂表格的需求,在消耗了大量脑细胞后,终于实现了这一需求,现在就把我的实现思路和代码总结一下,为需要的小伙伴做个参考。

产品需求

  • 合并相同数据的单元格(仅合并列);
  • 内容不固定,需要动态合并;
  • 指定合并列;
  • 数据相同但所属父级不一致的单元格不合并;
  • 空值不合并;

由于保密要求,所以不展示相关截图和数据,请大家见谅,这里只展示主要代码(代码注释已写,大家直接看就可以)。

模拟实际表格数据格式:

tableColumn: [
    { prop: 'School', label: '学校' },
    { prop: 'Grade', label: '年级' },
    { prop: 'Class', label: '班级' },
    { prop: 'Name', label: '姓名' },
    { prop: 'Chinese', label: '中文' },
    { prop: 'Math', label: '数学' },
    { prop: 'English', label: '英文' }
],
tableData: [
    {
      School: '第一小学',
      Grade: '1 年级',
      Class: '1 班',
      Name: '张三',
      Chinese: '90',
      Math: '100',
      English: '80'
    },
    ...
]

关键代码

抽成共用方法放到 utils 下,文件名根据需要自己起:

/**
 * 分析每一列,找出所有【列】可合并(数据相同)的单元格
 * @param {Array} tableData 表数据
 * @param {Array} tableColumn 表字段/表头
 * @param {Array} mergeCols 指定合并哪些列(字段)
 * @returns
 */
export const getMergeCells = (tableData = [], tableColumn = [], mergeCols = []) => {
  const fields = tableColumn?.map(v => v.prop)
  const array = []
  
  if (!tableData?.length || !tableColumn?.length || !mergeCols?.length) return
 
  // 倒叙遍历行(方便统计合并列单元格数至最上方,避免表格塌陷)
  for (let row = tableData.length - 1; row >= 0; row--) {
    array[row] = []
    for (let col = 0; col < fields.length; col++) {
       // 1.最后一行单元格不合并(初始无可对比数据)
       // 2.不在指定列(mergeCols)的单元格不合并
       // 3.空值不合并
      if (row === tableData.length - 1 || !mergeCols.includes(fields[col]) || !tableData[row][fields[col]]) {
        array[row][col] = [1, 1]
        continue
      }

      // 4.数据相同但所属父级不一致的单元格不合并
      const parentFields = mergeCols.slice(0, col) // 在指定合并列中找出所有父级
      if (mergeCols.includes(fields[col]) && parentFields?.includes(fields[col - 1])) {
        const currentParents = parentFields.map(field => tableData[row][field]) // 当前单元格所有父级
        const nextRowParents = parentFields.map(field => tableData[row + 1][field]) // 下一行单元格所有父级
        if (currentParents?.toString() !== nextRowParents?.toString()) {
          array[row][col] = [1, 1]
          continue
        }
      }

      // 5.合并相同数据的单元格
      if (tableData[row][fields[col]] === tableData[row + 1][fields[col]]) {
        const beforeCell = array[row + 1][col]
        array[row][col] = [1 + beforeCell[0], 1]
        beforeCell[0] = 0
        beforeCell[1] = 0
      } else {
        array[row][col] = [1, 1] // 否则不合并
      }
    }
  }
  // console.log(array, 'array')
  return array
}

优点:

  • 可动态指定需要合并的列
  • 空值(null、undefined、空字符串、0)不会被合并
  • 数据相同但所属父级不相同的不会被合并,并且不用手动指定父级
  • 支持分页

缺点:

  • 不支持相邻的行合并(大家有需要可自行修改)

如何使用

在 computed 下:

computed: {
    // 获取所有单元格合并数据
    spanArr() {
      if (!this.tableColumn.length) return []
      const mergeCols = ['School', 'Grade'] // 需要合并的列(字段)
      return getMergeCells(this.tableData, this.tableColumn, mergeCols)
    }
},

methods 方法:

methods: {
    // 表数据合并
    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
      return this.spanArr[rowIndex][columnIndex]
    }
}

el-table 组件主要靠 span-method 方法实现合并,所以将 objectSpanMethod 方法写在 span-method 上,即可实现。

注意:在实际异步获取的数据中,如果后端没有将数据进行排序返回,前端获取数据后需要对其进行排序处理,这样相邻的数据才能更好合并。

比如,我就是上面情况,后端返回数据后,我是先在 then 里面对需要合并的数据进行排序,然后在合并列:

await getUserUtilizationRate({date: this.dateValue, staff, appeal_type, task_id}).then((res) => {
  let sortedData = res.data.sort((a, b) => {
    // 先按 staff 排序
    if (a.staff < b.staff) return -1; if (a.staff > b.staff) return 1;

    // staff 相同,按 appeal_type 排序
    if (a.appeal_type < b.appeal_type) return -1; if (a.appeal_type > b.appeal_type) return 1;

    // appeal_type 相同,按 detail_appeal_type 排序
    if (a.detail_appeal_type < b.detail_appeal_type) return -1; if (a.detail_appeal_type > b.detail_appeal_type) return 1;

    return 0;
  })
  this.tableData = sortedData
})

结语

以上就是 vue 结合 elementui 的 el-table 实现动态合并可指定列数据相同的单元格实现方法的详细内容,希望对大家有用。

标签:el-table