Vue+el-table实现不规则表格

简介: Vue+elemenntUI

比如:我们要实现下图这个表格
在这里插入图片描述
代码如下:

<template>
  <div>
    <el-table :data="tableData" :span-method="objectSpanMethod" border :header-cell-style="handerMethod">
      <el-table-column align="center" prop="id" label=""></el-table-column>
      <el-table-column align="center" prop="amount1" label="数据分类"></el-table-column>
      <el-table-column align="center" prop="amount2" label="缴存业务"></el-table-column>
      <el-table-column align="center" prop="amount3" label="提取业务"></el-table-column>
      <el-table-column align="center" prop="amount4" label="贷款业务"></el-table-column>
      <el-table-column align="center" label="业务办理合计">
        <el-table-column align="center" label="业务办理合计" prop="amount5"></el-table-column>
        <el-table-column align="center" label="" prop="amount6"></el-table-column>
      </el-table-column>
    </el-table>
  </div>
</template>
<script>
export default {
  data() {
    return {
      spanArr: [], // 用于存放每一行记录的合并数
      tableData: [
        {
          id: '业务办理类业务统计量',
          amount1: '线上服务量小计',
          amount2: '1',
          amount3: '2',
          amount4: '3',
          amount5: '4',
          amount6: '4'
        },
        {
          id: '业务办理类业务统计量',
          amount1: '线上业务小计',
          amount2: '1',
          amount3: '2',
          amount4: '3',
          amount5: '4',
          amount6: '4'
        },
        {
          id: '业务办理类业务统计量',
          amount1: '线下业务小计',
          amount2: '1',
          amount3: '2',
          amount4: '3',
          amount5: '4',
          amount6: '4'
        },
        {
          id: '业务办理类业务统计量',
          amount1: '线上+线下',
          amount2: '1',
          amount3: '2',
          amount4: '3',
          amount5: '4',
          amount6: '4'
        },
        {
          id: '业务办理类业务统计量',
          amount1: '线上占比',
          amount2: '1',
          amount3: '2',
          amount4: '3',
          amount5: '4',
          amount6: '4'
        },
        {
          id: '9大渠道服务总量统计',
          amount1: '9大渠道服务总量统计',
          amount2: '信息查询',
          amount3: '信息发布',
          amount4: '互动交流',
          amount5: '业务办理',
          amount6: '线上总计'
        },
        {
          id: '9大渠道服务总量统计',
          amount1: '9大渠道服务总量统计',
          amount2: '01',
          amount3: '02',
          amount4: '03',
          amount5: '04',
          amount6: '05'
        }
      ]
    }
  },
  mounted() {
  },
  methods: {
    // 隐藏表头
    handerMethod({ rowIndex }) {
      if (rowIndex === 1) {
        // 这里为了是将第二列的表头隐藏,就形成了合并表头的效果
        return { display: 'none' }
      }
    },
    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
      // 对第六、七行 进行合并
      if (rowIndex === 5) {
        if (columnIndex === 0) {
          return [2, 2]
        } else if (columnIndex === 1) {
          return [0, 0]
        }
      }
      // 对第一列 第二列 进行合并
      if (columnIndex === 1 || columnIndex === 0) {
        // 当 当前行与上一行内容相同时 返回0 0 意味消除
        if (rowIndex > 0 && row[column.property] === this.tableData[rowIndex - 1][column.property]) {
          return {
            rowspan: 0,
            colspan: 0
          }
        } else {
          let rows = 1
          // 反之 查询相同的内容有多少行 进行合并
          for (let i = rowIndex; i < this.tableData.length - 1; i++) {
            if (row[column.property] === this.tableData[i + 1][column.property]) {
              rows++
            }
          }
          // 返回相同内容的行数
          return {
            rowspan: rows,
            colspan: 1
          }
        }
      }
      // 对第一、二、三、四、五行 进行合并
      if (rowIndex === 0 || rowIndex === 1 || rowIndex === 2 || rowIndex === 3 || rowIndex === 4) {
        // 处理合计,[1,2]表示合并1行2列,[0,0]表示改行不显示
        if (columnIndex === 5) {
          // 定位到5列的一、二、三、四、五行,告诉该单元格合并1行2列
          return [1, 2]
        } else if (columnIndex === 6) {
          // 定位到6列的一、二、三、四、五行,告诉该单元格不显示
          return [0, 0]
        }
      }
    }

  }
}
</script>

el-table 行合并

方法一:(直接使用)

<el-table
                :data="tableData"
                border
                :span-method="objectSpanMethod"
                style="width: 100%">
                <el-table-column
                prop="order"
                label="序号"
                align="center"
                width="50">
                </el-table-column>
                <el-table-column
                prop="name"
                :label="'名称'"
                align="center"
                fixed="left"
                width="70">
                </el-table-column>
</el-table>



<script>
export default {
  name: 'StationsStaTable',
  data () {
    return {
        tableData: [],
    },
 methods: {
    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
// 对第一列 第二列 进行合并
        if (columnIndex === 1 || columnIndex === 0) {
            // 当 当前行与上一行内容相同时 返回0 0 意味消除
            if(rowIndex > 0 && row[column.property] === this.tableData[rowIndex - 1][column.property]){
                return {
                    rowspan: 0,
                    colspan: 0
                };
            }else{
                let rows = 1;
                // 反之 查询相同的内容有多少行 进行合并
                for(let i = rowIndex; i < this.tableData.length - 1; i++){
                    if (row[column.property] === this.tableData[i + 1][column.property]) {
                        rows++;
                    }
                }
                // 返回相同内容的行数
                return {
                    rowspan: rows,
                    colspan: 1
                };
            }
        }
      }
 }

方法二:(封装函数)

1、使用

导入js文件,并设置需要合并的列

//导入js文件(文件脚本内容在下文)
import {getRowspanMethod} from '@/hook/el-tables/use-span-method.js'

//调用函数并导出需要的合并列函数 注意需要根据
//data为查询到的数据
//['prop1', 'prop2', 'prop3'] 需要合并的列
const spanMethod=getRowspanMethod(data,['prop1', 'prop2', 'prop3'])

在vue页面模板中使用

<!--使用spanMethod方法-->
<el-table :data="data" height="100%" :span-method="spanMethod">
...
</el-table>

2、封装合并的方法

这个文件(use-span-method.js)通过导出一个函数来提供给el-table的和并方法使用

/**
 * 合并相同数据,导出合并列所需的方法(只适合el-table)
 * @param {Object} data
 * @param {Object} rowspanArray
 */
export function getRowspanMethod(data, rowspanArray) {

    /**
     * 要合并列的数据
     */
    const rowspanNumObject = {};

    //初始化 rowspanNumObject
    rowspanArray.map(item => {
        rowspanNumObject[item] = new Array(data.length).fill(1, 0, 1).fill(0, 1);
        rowspanNumObject[`${item}-index`] = 0;
    });
    //计算相关的合并信息
    for (let i = 1; i < data.length; i++) {
        rowspanArray.map(key => {
            const index = rowspanNumObject[`${key}-index`];
            if (data[i][key] === data[i - 1][key]) {
                rowspanNumObject[key][index]++;
            } else {
                rowspanNumObject[`${key}-index`] = i;
                rowspanNumObject[key][i] = 1;
            }

        });
    }

    //提供合并的方法并导出
    const spanMethod = function({ row, column, rowIndex, columnIndex }) {
        if (rowspanArray.includes(column['property'])) {
            const rowspan = rowspanNumObject[column['property']][rowIndex];
            if (rowspan > 0) {
                return { rowspan: rowspan, colspan: 1 }
            }
            return { rowspan: 0, colspan: 0 }
        }
        return { rowspan: 1, colspan: 1 }
    };

    return spanMethod;
}

3、vue2/3具体使用

// vue2
import {getRowspanMethod} from '@/hook/el-tables/use-span-method.js'
    export default {
        data(){
            spanMethod:()=>{},
            list:[],
        },
        methods:{
            // 查询数据方法
            getData(){
                this.spanMethod=getRowspanMethod(this.list,['prop1', 'prop2', 'prop3'])
            }
        }
    }
 
// vue3 setup
import {ref ,computed} from 'vue';
    import {getRowspanMethod} from '@/hook/el-tables/use-span-method.js'
    
    // 获取数据存放变量
    let list=ref([]);
    //实际根据业务灵活调整
    const spanMethod=computed(()=>{
        return getRowspanMethod(list.value,['prop1', 'prop2', 'prop3'])
    })
    
    // 查询数据方法
    const getData=function(){
        //查询到数据赋值
        list.value=[];
    }

el-table 列合并

objectSpanMethod({ row, column, rowIndex, columnIndex }) {
      // 处理合计,[1,2]表示合并2行2列,[0,0]表示改行不显示
      if (rowIndex === 5) {
        if (columnIndex === 0) {
          // 定位到0列,告诉该单元格合并1行2列
          return [1, 2]
        } else if (columnIndex === 1) {
           // 定位到1列,告诉该单元格不显示
          return [0, 0]
        }
      }
    }

el-table表头列合并

<el-table :data="tableData" :header-cell-style="handerMethod">
    <el-table-column align="center" label="业务办理合计">
            <el-table-column label="业务办理合计" prop="amount5"></el-table-column>
            <el-table-column label="" prop="amount6"></el-table-column>
          </el-table-column>
</el-table>
    //隐藏表头
    handerMethod({rowIndex}){
      if (rowIndex === 1) {
       //这里为了是将第二列的表头隐藏,就形成了合并表头的效果
        return {display: 'none'}
      }
    },
       <el-table-column label="业务办理合计" prop="amount5"></el-table-column>
        <el-table-column label="" prop="amount6"></el-table-column>
      </el-table-column>

//隐藏表头
handerMethod({rowIndex}){
  if (rowIndex === 1) {
   //这里为了是将第二列的表头隐藏,就形成了合并表头的效果
    return {display: 'none'}
  }
},
## el-table自定义合计

**效果图如下:**![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/8c9d932c73334f9a99671a300d7f5bb3.png)**代码实现:**

return {
  tableData: [
    {       
      name: '张三',
      sex: '男',
      tiZh: 120,
      num1: 1000,
      num2: 2000,
      num3: 3000
    },{       
      name: '张四',
      sex: '女',
      tiZh: 120,
      num1: 1000,
      num2: 2000,
      num3: 3000
    },
  ],
}

},
computed: {},
mounted() {},
methods: {

objectSpanMethod() {
  this.$nextTick(x => {
  if (this.$refs.table.$el) {
      var current = this.$refs.table.$el
        .querySelector(".el-table__footer-wrapper")
        .querySelector(".el-table__footer");
      var cell = current.rows[0].cells;
      cell[0].style.display = "none";
      cell[1].style.display = "none";
      cell[2].style.display = "none";
      cell[3].classList.remove('is-left')
      cell[3].colSpan = "4";
    }
  })
},
getNodeSummaries(param) {
  const { columns, data } = param;
  const sums = [];
  let arr = [ 'num1', 'num2', 'num3']
  columns.forEach((column, index) => {
    if (index === 3) {
      sums[index] = "合计";
      return;
    }
    if (arr.some(x => column.property === x)) {
      sums[index] = 0;
      data.map((item) => {
        console.log(item)
        let num = item[column.property];
        // num = num ? parseFloat(num.replace(/,/gi, "")) : 0;
        sums[index] = this.accAdd(sums[index], num);
      });
    } else {
      sums[index] = "";
    }
  });
  return sums;
},
accAdd(arg1, arg2) {
  let r1, r2, m;
  try {
    r1 = arg1.toString().split(".")[1].length;
  } catch (e) {
    r1 = 0;
  }
  try {
    r2 = arg2.toString().split(".")[1].length;
  } catch (e) {
    r2 = 0;
  }
  m = Math.pow(10, Math.max(r1, r2));
  return ((arg1 * m + arg2 * m) / m).toFixed(2);
},

}
}

width: 50%;
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);

}

目录
相关文章
|
17天前
|
JavaScript API 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
17天前
|
JavaScript 前端开发 开发者
Vue是如何劫持响应式对象的
Vue是如何劫持响应式对象的
19 1
|
17天前
|
JavaScript 前端开发 API
介绍一下Vue中的响应式原理
介绍一下Vue中的响应式原理
26 1
|
17天前
|
JavaScript 前端开发 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
17天前
|
存储 JavaScript 前端开发
介绍一下Vue的核心功能
介绍一下Vue的核心功能
|
存储 前端开发 JavaScript
为什么我不再用Vue,改用React?
当我走进现代前端开发行业的时候,我做了一个每位开发人员都要做的决策:选择一个合适的框架。当时正逢 jQuery 被淘汰,前端开发者们不再用它编写难看的、非结构化的老式 JavaScript 程序了。
|
19天前
|
JavaScript 前端开发 开发者
vue 数据驱动视图
总之,Vue 数据驱动视图是一种先进的理念和技术,它为前端开发带来了巨大的便利和优势。通过理解和应用这一特性,开发者能够构建出更加动态、高效、用户体验良好的前端应用。在不断发展的前端领域中,数据驱动视图将继续发挥重要作用,推动着应用界面的不断创新和进化。
|
20天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
23 1
vue学习第一章
|
20天前
|
JavaScript 前端开发 索引
vue学习第三章
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中的v-bind指令,包括基本使用、动态绑定class及style等,希望能为你的前端学习之路提供帮助。持续关注,更多精彩内容即将呈现!🎉🎉🎉
22 1
vue学习第三章
|
20天前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
35 1
vue学习第四章