el-table每隔数行生成一个小计,最终生成一个合计

发布时间 2023-06-20 18:14:43作者: RicardoX3
  • element本身功能已经很齐全了,但实际开发中肯定会伴随着各种奇葩要求,譬如根据日期统计几行的【小计】,然后最终再根据所有小计数据统计出【合计】。
  • show me the code!
  • 首先,el-table提供的自定义合计方法返回的是一个数组,其数组项就是对应列的数据,譬如第0列一般是序号,第5列是需要统计的那么 sums[4] = 42 就会在最终渲染时让该列的【合计】行上显示42。因此无论是根据表格当前分页数据计算而来,还是后端返回的统计数据,都可以在只需要合计行的情况下轻松设置。

 

  • 若是需要小计,个人想到的方法是修改表格数据,在需要的地方插入一条新数据,以此实现需求
  • 注:该方法是更改data本身,因此数据长度必定发生变化,以及默认的序号列(type="index")会标记小计与合计行。若是有分页需求的,请考虑在修改完数据后修改分页器的size(最大显示条目数)确保所有数据能够渲染;若是有序号标记需求的,请手动设置序号列(prop=“index”)并在正确的数据上设置该值。
    • //计算小计
      const processData = computed(()=>{
        let subtotal = 0 //小计数量
        let temp = [] //重新渲染的数组
        let division = 0 //以日期作为合计分割点
        testData.value.forEach((item, index)=>{
          //给原数据添加序号
          item.index = index + 1
          temp.push(item)
          //同一个日期内
          if(item.findate === testData.value[index + 1]?.findate){
            //同一个站
            if(item.locationname === testData.value[index + 1]?.locationname){
              //同一种票
              if(item.tickettypename === testData.value[index + 1]?.tickettypename){
                subtotal += item.ticketnum
              } else {//不同票据
                subtotal += item.ticketnum
                temp.push({index: null, tickettypename: '小计', ticketnum: subtotal})
                subtotal = 0
              }
            } else{//不同站点
              subtotal += item.ticketnum
              temp.push({index: null, tickettypename: '小计', ticketnum: subtotal})
              subtotal = 0
            }
          } else {//不同日期,添加一个小计与合计
            subtotal += item.ticketnum
            temp.push({index: null, tickettypename: '小计', ticketnum: subtotal})
            subtotal = 0
            temp.push({index: '', tickettypename: '总计', ticketnum: testData.value.slice(division, index + 1).reduce((total, item) => total + item.ticketnum, 0)})
            division = index + 1 //新的分割点
          }
        })
        state.pagination.total = temp.length
        state.pagination.size = temp.length
        return temp
      })
      //渲染小计和总计的样式
      const rowStyle = ({row}) => {
        if(row.tickettypename === '小计') return ('background: #EFEFEF; color: red')
        else if(row.tickettypename === '总计') return ('background: #FCCFDB; font-weight: 700')
      }

      实际效果如下

    • 计算逻辑可以自己写。我这里使用了分页,渲染完毕后把分页器的size设置为了新数据的长度,total不变(毕竟你切页的时候是请求新数据了,譬如21~40的原始数据,前一页渲染了多少行不影响);

    • 同时序号是自定义的列;

知识点:

1、object?.property:【?.】是语法糖,能够避免访问undefined的属性而报错,譬如

 obj = {age: 18}, obj.name.length //error! 

obj.name?.length //undefined

2、array.reduce(function(total, currentValue, currentIndex, arr), initialValue):这是个遍历数组的方法(用作累加器),第一个参数为回调函数,第二个参数为累加初始值。

total为传入下次回调的值,若是设置初始值则为初始值,否则为数组第一项;

currentValue为数组当前元素;

currentIndex为数组当前元素索引;

arr为当前元素所属数组(直接用array也可以)

//譬如有数组如下

let arr = [4,10,22,10]

arr.reduce((toal, item)=>total + item) //output: 46

3、一开始要让我适应组合式API写法是拒绝的,因为下意识的认为这是绑定TS语法,类型判断实在是太过吹毛求疵了(对于目前的项目而言),而且选项式API风格很标准,依赖、组件、变量、方法、生命周期钩子一目了然,该放哪儿就在哪儿。但之后发现这样写出来的在后期维护修bug的时候很折磨(尤其是我的idea现在导向声明时灵时不灵)。于是我转向了组合式风格,不得不说实在是太爽了。引入依赖、变量声明、方法全都可以扎堆写成一坨,维护的时候一找就能全部找到了,写起来也很爽(可能这就是屎山初体验吧哈哈哈,因为我看element的示例demo里,他们还是很标准地将类型声明、依赖引入、变量、方法各自分在一块儿,没有聚在一起)