Vue - Element el-table 表头、行、列合并,底部或顶部显示汇总行

GitHub Demo 地址

在线预览

效果图

在这里插入图片描述

要点

使用el-tablespan-method方法合并行和列
使用el-tableheader-cell-style方法合并表头
使用el-tablecell-class-name方法配合css样式隐藏Checkbox
使用el-tableshow-summarysummary-method方法配合css样式设置汇总行和汇总行样式

代码

<template>
  <div class="app-container">

    <el-table
      id="table"
      ref="tableRef"
      :data="singleOrderData"
      border
      :span-method="arraySpanMethod"
      :header-cell-style="headerCellStyle"
      :cell-class-name="cellClassName"
      :cell-style="cellStyle"
      show-summary
      :summary-method="getSummaries"
      @selection-change="selectionChangeHandle"
    >
      <el-table-column v-if="isShowCheckbox" type="selection" width="55" />
      <!-- productName use productPlaceholder field  -->
      <el-table-column label="Product" prop="productPlaceholder" width="150" />
      <el-table-column label="Product" prop="productName" align="center" width="600" />
      <el-table-column label="Quantity" prop="quantity" align="center" width="100" />
      <el-table-column label="Price" align="center" width="150">
        <template slot-scope="scope">
          <span>${{ scope.row.price }}</span>
        </template>
      </el-table-column>
      <el-table-column label="Unit Discount" align="center" width="150">
        <template slot-scope="scope">
          <div v-if="!scope.row.isChildren">
            <p>-${{ scope.row.discount }}</p>
            <p v-if="scope.row.discountNotes">
              <el-tag size="small" type="primary">{{ scope.row.discountNotes }}</el-tag>
            </p>
          </div>
          <div v-else>
            <span>Combo Discount: -${{ scope.row.memberProductDiscount }}</span>
          </div>
        </template>
      </el-table-column>
      <el-table-column label="Total" align="center" width="150">
        <template slot-scope="scope">
          <span>${{ scope.row.subTotal }}</span>
        </template>
      </el-table-column>

    </el-table>

  </div>
</template>

<script>
// import { getDeptList } from '@/api/base/base'
// import { getDictLevel, getListData, getDataById, addData, deleteData, editData, exportById } from '@/api/tables/tables'
export default {
  components: {},
  data() {
    return {
      singleOrderData: [],
      isShowCheckbox: true,
      selectionList: [] // 勾选一行或多行数据
    }
  },
  created() {
    this.testData()
    this.singleOrderData = this.handleData(this.singleOrderData)
  },
  mounted() {
    if (this.isShowCheckbox && this.singleOrderData.length) {
      this.$refs.tableRef.toggleAllSelection()
      // this.$nextTick(() => {
      //   this.$refs.tableRef.toggleAllSelection()
      // })
    }
  },
  methods: {
    testData() {
      this.singleOrderData = [
        {
          productId: '1',
          productName: 'testCombo',
          discount: 0,
          quantity: 1,
          price: 200,
          subTotal: 200,
          discountNotes: 'Combo Discount',
          memberProductDiscount: 397,
          productMemberList: [
            {
              productId: '1-1',
              productName: 'testCombo - child1',
              quantity: 1,
              price: 499,
              subTotal: 200,
              discount: 331.83,
              discountNotes: 'Combo Discount'
            },
            {
              productId: '1-2',
              productName: 'testCombo - child2',
              quantity: 2,
              price: 49,
              subTotal: 400,
              discount: 32.58,
              discountNotes: 'Combo Discount'
            }
          ]
        },
        {
          productId: '2',
          productName: 'product',
          discount: 0,
          quantity: 1,
          price: 89,
          subTotal: 89,
          discountNotes: '',
          memberProductDiscount: 0,
          productMemberList: []
        }
      ]
    },
    // 数据转成平级
    handleData(singleOrderData) {
      var newArr = []
      for (let i = 0; i < singleOrderData.length; i++) {
        singleOrderData[i].productPlaceholder = singleOrderData[i].productName
        const product = singleOrderData[i]
        const newProduct = { ...singleOrderData[i] }
        delete newProduct.productMemberList
        newProduct.isNormalProduct = !product.productMemberList.length
        newArr.push(newProduct)
        if (product.productMemberList && product.productMemberList.length) {
          for (let j = 0; j < product.productMemberList.length; j++) {
            product.productMemberList[j].isStart = j === 0
            product.productMemberList[j].row = product.productMemberList.length
            product.productMemberList[j].isChildren = true
            product.productMemberList[j].productPlaceholder = 'Which includes:'
            product.productMemberList[j].memberProductDiscount = product.memberProductDiscount
            newArr.push(product.productMemberList[j])
          }
        }
      }
      return newArr
    },
    selectionChangeHandle(val) {
      this.selectionList = val
      console.log(JSON.stringify(this.selectionList))
    },
    // 设置表头样式 - 合并表头
    headerCellStyle({ row, column, rowIndex, columnIndex }) {
      if (row[0].level === 1) {
        // row[0].colSpan = 0
        row[1].colSpan = 2
        row[2].colSpan = 0
        const tempColumn = this.isShowCheckbox ? 2 : 0
        if (columnIndex === tempColumn) {
          return { display: 'none' }
        }
      }
      return { textAlign: 'center', background: '#E6E6E6' }
    },
    // 设置表内容样式
    cellStyle({ row, column, rowIndex, columnIndex }) {
      return { textAlign: 'center' }
    },
    // 隐藏Checkbox
    cellClassName({ row, column, rowIndex, columnIndex }) {
      if (columnIndex === 0) {
        if (row.isNormalProduct || row.isChildren) {
          //
        } else {
          return 'disabled-column'
        }
      }
    },
    // 合并行或列
    arraySpanMethod({ row, column, rowIndex, columnIndex }) {
      // console.log('rowIndex=' + rowIndex + '-----' + 'columnIndex=' + columnIndex)
      // console.log('row')
      // console.log(JSON.stringify(row))
      // console.log('column')
      // console.log(JSON.stringify(column))
      // header
      // father
      if (column['property'] === 'productPlaceholder' && !row.isChildren) {
        return [1, 2]
      }
      if (column['property'] === 'productName' && !row.isChildren) {
        return [0, 0]
      }
      // children
      if (column['property'] === 'productPlaceholder' && row.isChildren && row.isStart) {
        return [row.row, 1]
      }
      if (column['property'] === 'productPlaceholder' && row.isChildren && !row.isStart) {
        return [0, 0]
      }
      // footer
      if (column['label'] === 'Unit Discount' && row.isChildren && row.isStart) {
        return [row.row, 2]
      }
      if (column['label'] === 'Unit Discount' && row.isChildren && !row.isStart) {
        return [0, 0]
      }
      if (column['label'] === 'Total' && row.isChildren && row.isStart) {
        return [0, 0]
      }
      if (column['label'] === 'Total' && row.isChildren && !row.isStart) {
        return [0, 0]
      }
    },
    // 汇总合计计算 - 自定义
    getSummaries(param) {
      var tempData = this.singleOrderData
      var allQuantity = 0
      var allMoney = 0
      for (let i = 0; i < tempData.length; i++) {
        const product = tempData[i]
        // 计算总数量(只计算子产品和普通产品)
        if (product.isChildren || product.isNormalProduct) {
          allQuantity += product.quantity
        }
        // 计算总金额(只计算父产品和普通产品)
        if (!product.isChildren || product.isNormalProduct) {
          allMoney += product.subTotal
        }
      }
      // sums数组的每一个元素代表表格从左到右的列(column)
      const sums = []
      sums[0] = '合计'
      sums[2] = '总数量: ' + allQuantity
      sums[5] = '总金额: $' + allMoney
      if (!this.isShowCheckbox) {
        // 计算汇总合计后,合并footer(也可以设置样式)
        // 需要在<el-table id="table">
        this.$nextTick(() => {
          const tds = document.querySelectorAll('#table .el-table__footer-wrapper tr>td')
          // colSpan合并列
          tds[1].colSpan = 1
          tds[2].style.color = 'orange'
          // tds[3].style.textAlign = 'center'
          // tds[4].style.display = 'none'
        })
      }
      return sums
    },
    // 汇总合计计算 - 官网方法
    getSummaries2(param) {
      const { columns, data } = param
      const sums = []
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = '总价'
          return
        }
        const values = data.map((item) => Number(item[column.property]))
        if (!values.every((value) => isNaN(value))) {
          sums[index] = values.reduce((prev, curr) => {
            const value = Number(curr)
            if (!isNaN(value)) {
              return prev + curr
            } else {
              return prev
            }
          }, 0)
          sums[index] += ' 元'
        } else {
          sums[index] = 'N/A'
        }
      })
      return sums
    }
  }
}
</script>

<style lang="scss" scoped>
::v-deep {
  .disabled-column .el-checkbox__input {
    display: none;
  }
  // 解决el-table的合计行在横向滚动条下方的问题
  .el-table {
    overflow: auto;
  }
  .el-table__header-wrapper,
  .el-table__body-wrapper,
  .el-table__footer-wrapper {
    overflow: visible;
  }
  .el-table__body-wrapper {
    overflow-x: visible !important;
  }
  // 解决前面样式覆盖之后伪类带出来的竖线
  .el-table::after {
    position: relative;
  }
  // 合计字体颜色
  .el-table__footer-wrapper tbody td:first-child {
    color: red;
    cursor: auto;
  }
  // 合计行字体颜色
  .el-table__footer-wrapper tbody td {
    color: #409eff;
    cursor: pointer;
  }
  // // order默认值为0,只需将表体order置为1即可移到最后,这样总计行就上移到表体上方
  // .el-table {
  //   display: flex;
  //   flex-direction: column;
  // }
  // .el-table__body-wrapper {
  //   order: 1;
  // }
}
</style>
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值