让前端飞前端开发记录web前端技术分享

element ui 表格动态列,单行合并同时可行内编辑

2022-11-17  本文已影响0人  阿巳交不起水电费

效果如下:


image.png
image.png

版本信息如下:

"vue": "^2.5.2", "element-ui": "^2.7.2",

代码如下:

<!--表格行合并-->
<template>
  <div style="margin: 20px">
    <div style="margin: 20px 0;text-align: right;">
      <el-button type="primary" @click="logTableData">打印表格数据</el-button>
    </div>
    <el-table
      v-loading="tableLoading"
      :data="tableData"
      :span-method="spanMethod"
      :header-row-style="headerRowStyle"
      style="width: 100%">

      <el-table-column
        align="center"
        v-for="(col,colIndex) in tableHeader"
        :key="`col-${colIndex}`"
        :prop="col.prop"
        :min-width="col.width || 80"
        :label="col.label">
        <template slot-scope="{row, $index}">
          <el-input v-if="!col.noEdit && row._edit" class="inputNumber" :placeholder="`请输入${col.label}`"
                    v-model="row[col.prop]"/>
          <span v-else>{{ row[col.prop] }}</span>
        </template>
      </el-table-column>

      <el-table-column align="center" label="配比">
        <el-table-column label="" align="center" v-for="rateColIndex in maxTableColLength" :key="`rate-${rateColIndex}`"
                         :min-width="80">
          <template slot-scope="{row, $index}">


            <!--                第一行-->
            <template v-if="row.rowSpan">
              <span v-if="rateColIndex <= row.list.length">{{ row.list[rateColIndex - 1].name }}</span>
            </template>

            <!--                第二行,操作的也是上一行的数据-->
            <!--              有这项的才可编辑-->
            <template v-else-if="rateColIndex <= tableData[$index-1].list.length">

              <el-input class="inputNumber" type="number" v-if="tableData[$index-1]._edit" placeholder="请输入"
                        v-model="tableData[$index-1].list[rateColIndex-1].rate"/>
              <span v-else>{{ valFixed(tableData[$index-1].list[rateColIndex - 1].rate, 2) }}</span>

            </template>

          </template>
        </el-table-column>
      </el-table-column>

      <el-table-column
        fixed="right"
        align="center"
        label="操作"
        width="120">
        <template slot-scope="{row,$index}">
          <template v-if="!row._edit">
            <el-button @click="rowEdit(row, $index)" type="text">修改</el-button>
          </template>
          <template v-else>
            <el-button @click="rowSave(row, $index)" type="text">保存</el-button>
            <el-button @click="rowCancel(row, $index)" type="text">取消</el-button>
          </template>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      tableLoading: false,
      tableHeader: [
        {
          prop: 'pileNo',
          label: '堆号',
          noEdit: true
        },
        {
          prop: 'tfe',
          label: '品位'
        },
        {
          prop: 'ironWeight',
          label: '铁水产量'
        }
      ],
      tableData: [],
      historyRow: null, // 行编辑时存储历史数据
    }
  },
  computed: {
    // 表格中最大配比列长度
    maxTableColLength() {
      let arr = this.tableData.map(item => {
        return (item.list || []).length
      })
      return arr.length ? Math.max(...arr) : 0
    },
  },
  created() {
    this.initData()
  },
  methods: {
    // 判断值是否为空
    isNull(val) {
      return val === null || val === void 0 || val === '' || (val).toString() === 'NaN'
    },
    /**
     * 值保留小数处理
     * @val: 需要保留小数的值
     * @fixed:小数位数
     * @dt:为空时的默认值
     * @unit:单位
     * */
    valFixed(val, fixed = 3, dt = '', unit = '') {
      return this.isNull(val) ? dt : (parseFloat(val).toFixed(fixed) + unit)
    },
    initData() {
      // 模拟数据
      let data = [
        {
          pileNo: '11111111',
          tfe: 56.2,
          ironWeight: 5000,
          list: [
            {
              name: '精粉1',
              rate: 10,
            },
            {
              name: '精粉2',
              rate: 5,
            },
            {
              name: '混合粉2',
              rate: 8,
            },
            {
              name: '混合粉4',
              rate: 3,
            }
          ],
        },
        {
          pileNo: '22222222',
          tfe: 50.34,
          ironWeight: 5500,
          list: [
            {
              name: '精粉5',
              rate: 10,
            },
            {
              name: '混合粉1',
              rate: 8,
            },
            {
              name: '混合粉2',
              rate: 3,
            }
          ],
        },
        {
          pileNo: '33333333',
          tfe: 49,
          ironWeight: 4900,
          list: [
            {
              name: '精粉5',
              rate: 5,
            },
            {
              name: '混合粉1',
              rate: 10,
            },
            {
              name: '混合粉2',
              rate: 20,
            },
            {
              name: '混合粉3',
              rate: 20,
            }
          ],
        }
      ]

      let tableData = []
      data.map(item => {
        let list = item.list || []
        tableData = tableData.concat([
          {
            ...item,
            // 辅助变量
            rowSpan: 2
          },
          {}
        ])
      })
      this.tableData = tableData
    },

    // 表头隐藏
    headerRowStyle({row, rowIndex}) {
      if (rowIndex === 1) {
        return {'display': 'none'}
      }
    },
    // 表格行合并
    spanMethod({row, column, rowIndex, columnIndex}) {
      let startColIndex = this.tableHeader.length // 数的,第五列开始是配比列
      let endColIndex = startColIndex + (this.maxTableColLength - 1)
      let isRateCol = columnIndex >= startColIndex && columnIndex <= endColIndex // 配比列不进行行合并
      if (row.rowSpan) { // name行
        if (!isRateCol) {
          return [row.rowSpan, 1]
        } else {
          return [1, 1]
        }
      } else { // 配比行
        if (!isRateCol) {
          return [0, 1]
        } else {
          return [1, 1]
        }
      }

    },

    // 打印数据
    logTableData() {
      let data = this.tableData.filter(item => item.rowSpan)
      data.map((item) => {
        let str = ''
        this.tableHeader.map(sub => {
          str += `${sub.label}: ${item[sub.prop]} `
        })
        item.list.map(sub => {
          str += `${sub.name}: ${sub.rate} `
        })
        console.log(`%c${str}`, 'color: #43bb88;font-weight: bold;');
      })

      console.log('最终数据为:', data)
    },

    // 行编辑 --------------- start

    // 修改
    rowEdit(row, rowIndex) {
      // console.log(row, rowIndex)
      if (this.tableData.find(item => item._edit)) return this.$message({
        message: '请保存正在编辑的行',
        type: 'warning'
      });

      let editRow = row
      this.historyRow = JSON.parse(JSON.stringify(editRow))
      this.$set(editRow, '_edit', true)
    },
    // 保存正在编辑的
    rowSave(row, rowIndex) {
      // console.log(row, rowIndex)
      this.historyRow = {}
      row._edit = false
    },
    // 取消保存
    rowCancel(row, rowIndex) {
      // console.log(row, rowIndex)
      this.tableData.splice(rowIndex, 1, {
        ...this.historyRow,
        _edit: false
      })
      this.historyRow = {}
    }

    // 行编辑 --------------- end
  }
}
</script>

<style scoped lang="less">

.inputNumber {
  /deep/ input::-webkit-outer-spin-button,
  /deep/ input::-webkit-inner-spin-button {
    -webkit-appearance: none !important;
  }

  /deep/ input[type='number'] {
    -moz-appearance: textfield;
  }
}
</style>

大体思路

image.png

1.表头其实有两行,下面这行被隐藏了。
2.表格中每行数据是两行,表格行合并了,第二行是空行,编辑时操作的是第一行的数据。
3.这里使用行合并是为了让配比列表格宽度自适应。

若对你有帮助,请点个赞吧,谢谢支持!
本文地址:https://www.jianshu.com/p/0fdfbb68a73e?v=1668668903593,转载请注明出处,谢谢。

上一篇下一篇

猜你喜欢

热点阅读