vue+elemet实现表格手动合并行列

1.初始化一个element的table表格,选中一个单元格选择合并行和列,参考element文档需要使用到的方法是objectSpanMethod,注意:objectSpanMethod参数行和列都是从0开始,比如第一行第一列单元格位置是(0,0),要合并的行和列最小为1
2.实现效果如下:
vue+elemet实现表格手动合并行列_第1张图片
vue+elemet实现表格手动合并行列_第2张图片
vue+elemet实现表格手动合并行列_第3张图片

3.代码如下:

<template>
    <div class="content">
        <div class="table_box" v-if="show">
             <el-table
                ref="singleTable"
                :data="tableData"
                highlight-current-row
                @current-change="handleCurrentChange"
                border
                :span-method="objectSpanMethod"
                @cell-dblclick = "dbclick"
                :cell-class-name="tableCellClassName"
                @cell-click="cellClick"
               >
                <el-table-column
                    v-for="(item,key,index) in tableColumns"
                    :key="index"
                    :label="item.label"
                    :prop="item.children?'':item.prop"
                    
                    width="180">
                    <el-popover
                        placement="right"
                        width="400"
                        slot-scope="scope"
                        trigger="click">
                        <el-button size="mini" type="primary" @click="dialogVisible = true">合并单元格</el-button>
                        <el-button size="mini" type="primary" @click="addTr('top',selectTab.tr)">向上插入一行</el-button>
                        <el-button size="mini" type="primary" @click="addTr('bottom',selectTab.tr)">向下插入一行</el-button>
                        <div slot="reference">
                            <span>{{ scope.row[item.prop] }}</span>
                        </div>
                    </el-popover>
                    <div v-if="item.children && item.children.length>0">
                        <el-table-column
                            v-for="(val,i) in item.children"
                            :key="i"
                            :prop="val.prop"
                            :label="val.label"
                            width="180">
                            <!-- <template slot-scope="scope">
                                <span>{{ scope.row[val.prop] }}22</span>
                            </template> -->
                            <el-popover
                                placement="right"
                                width="400"
                                slot-scope="scope"
                                trigger="click">
                                <el-button size="mini" type="primary" @click="dialogVisible = true">合并单元格</el-button>
                        <el-button size="mini" type="primary" @click="addTr('top',selectTab.tr)">向上插入一行</el-button>
                        <el-button size="mini" type="primary" @click="addTr('bottom',selectTab.tr)">向下插入一行</el-button>
                                <div slot="reference">
                                    <span>{{ scope.row[val.prop] }}</span>
                                </div>
                            </el-popover>
                        </el-table-column>
                    </div>
                </el-table-column>
                
            </el-table>
        </div>
        <el-dialog
        title="合并"
        :visible.sync="dialogVisible"
        width="300px"
        >
        <el-form ref="form" label-width="80px">
            <el-form-item label="合并行">
                <el-input :min="0" v-model="selectTab.trSpan"/>
            </el-form-item>
            <el-form-item label="合并列">
                <el-input :min="0" v-model="selectTab.tdSpan"/>
            </el-form-item>
        </el-form>
        <span slot="footer" class="dialog-footer">
            <el-button @click="dialogVisible = false" size="small">取 消</el-button>
            <el-button type="primary" @click="addMerge" size="small">确 定</el-button>
        </span>
        </el-dialog>
    </div>
</template>
<script>
export default {
    data(){
        return{
            tableData:[],//表格数据
            tableColumns:[],//表头数据    
            show:false,
            currentRow: null,
            spanArr:[],
            selectTab:{
                tr:0,//第几行
                td:0,//第几列
                trSpan:1,//占几行
                tdSpan:1,//占几列
            },
            mergeList:[],//记录合并详情
            dialogVisible:false,
        }
    },
    watch:{
        // mergeList:{//监听合并列表项
        //     handler(newVal,oldVal){
        //         console.log('刷新');
        //         this.show = false;
        //         this.$nextTick(()=>{
        //             this.show = true;
        //         })
        //     },
        //     deep:true
        // }
    },
    mounted(){
        this.init();
    },
    methods:{
        tableCellClassName({row, column, rowIndex, columnIndex}){
            //注意这里是解构
            //利用单元格的 className 的回调方法,给行列索引赋值
            row.index=rowIndex;
            column.index=columnIndex;
        },
        cellClick(row, column, cell, event){
            console.log('rowIndex',row.index);
            console.log('colIndex',column.index);
            this.selectTab.tr = row.index+1;
            this.selectTab.td = column.index+1;
        },

        dbclick(row, column, cell, event){
            console.log('row:',row);
            console.log('column:',column,);
            console.log('cell:',cell);
            console.log('event:',event);
            this.selectTab.tr = row.index+1;
            this.selectTab.td = column.index+1;
        },
        addMerge(){//合并项添加进合并列表中
            // let obj = this.mergeList.filter(item=>item.td==this.selectTab.td&&item.tr)
            let flag = false;
            let w = -1;
            this.mergeList.forEach((item,index)=>{
                if(item.td==this.selectTab.td && item.tr==this.selectTab.tr){//是否有重复项,有则替换
                    flag = true;
                    w = index;
                }
            })
            if(flag){
                this.mergeList[w] = Object.assign({},this.selectTab);
            }else{
                this.mergeList.push(Object.assign({},this.selectTab));
            }
           
            this.dialogVisible = false;
            this.show = false;//手动刷新
                this.$nextTick(()=>{
                    this.show = true;
                })
        },
        objectSpanMethod({ row, column, rowIndex, columnIndex }) {//表格的合并函数
            //console.log('列',columnIndex,rowIndex);
            //console.log('行',row,column);0,2
          
            // let td = Number(this.selectTab.td)-1;//columnIndex从0开始
            // let tr = Number(this.selectTab.tr)-1;//rowIndex从0开始
            // if( columnIndex>=td && columnIndex<=((Number(td)+Number(this.selectTab.trSpan))-1)){
            //     if( rowIndex>=tr && rowIndex<=((Number(tr)+Number(this.selectTab.tdSpan))-1)){
            //         if(columnIndex==td && rowIndex==tr){
            //             return [this.selectTab.tdSpan,this.selectTab.trSpan]
            //         }else{
            //             console.log('选择的行列',columnIndex,rowIndex);
            //             console.log('选择的列',this.selectTab.td,(Number(this.selectTab.td)+Number(this.selectTab.tdSpan))-1);
            //             console.log('选择的行',this.selectTab.tr,(Number(this.selectTab.tr)+Number(this.selectTab.trSpan))-1);
            //             return [0,0]
            //         }
            //     }
            // }
            if(this.mergeList.length>0){
                console.log('merge',this.mergeList);
                for(let i=0;i<this.mergeList.length;i++){
                    let item = this.mergeList[i];
                    let td = Number(item.td)-1;//columnIndex从0开始
                    let tr = Number(item.tr)-1;//rowIndex从0开始
                    if( columnIndex>=td && columnIndex<=((Number(td)+Number(item.trSpan))-1)){
                        if( rowIndex>=tr && rowIndex<=((Number(tr)+Number(item.tdSpan))-1)){
                            if(columnIndex==td && rowIndex==tr){
                                console.log('选中的行列',columnIndex,rowIndex,item.tdSpan,item.trSpan);
                                return [item.tdSpan,item.trSpan]
                            }else{
                                console.log('选择的行列',columnIndex,rowIndex);
                                // console.log('选择的列',this.selectTab.td,(Number(this.selectTab.td)+Number(this.selectTab.tdSpan))-1);
                                // console.log('选择的行',this.selectTab.tr,(Number(this.selectTab.tr)+Number(this.selectTab.trSpan))-1);
                                return [0,0]
                            }
                        }
                    }
                }
            }
            //forEach中使用return不会中断,相当于continue
            // this.mergeList.forEach(item=>{
            //     let td = Number(item.td)-1;//columnIndex从0开始
            //     let tr = Number(item.tr)-1;//rowIndex从0开始
            //     if( columnIndex>=td && columnIndex<=((Number(td)+Number(item.trSpan))-1)){
            //         if( rowIndex>=tr && rowIndex<=((Number(tr)+Number(item.tdSpan))-1)){
            //             if(columnIndex==td && rowIndex==tr){
            //                 console.log('选中的行列',columnIndex,rowIndex,item.tdSpan,item.trSpan);
            //                 return [item.tdSpan,item.trSpan]
            //             }else{
            //                 console.log('选择的行列',columnIndex,rowIndex);
            //                 // console.log('选择的列',this.selectTab.td,(Number(this.selectTab.td)+Number(this.selectTab.tdSpan))-1);
            //                 // console.log('选择的行',this.selectTab.tr,(Number(this.selectTab.tr)+Number(this.selectTab.trSpan))-1);
            //                 return [0,0]
            //             }
            //         }
            //     }
            // })
            
        },
        init(){//初始化表格
            // if(this.tdCount==0){
            //     this.tableColumns = [{label:'默认',prop:'default'}];
            //     this.tableData = [{default:0}];
            // }
            this.tableColumns = [
                {label:'默认',prop:'default'},
                {label:'双十一',prop:'',children:[{label:'库存',prop:'count'},{label:'销量',prop:'sale'}]},
            ];
            this.tableData = [
                {default:0,count:111,sale:100},
                 {default:0,count:173,sale:220},
                  {default:0,count:89,sale:120}
            ];
            this.show = true;
            
        },
        addTab(){//插入表头
            if(this.tableColumns.every(item=>item.label!=this.tab.label)){
                this.tableColumns.push(Object.assign({},this.tab));
            }else{
                this.$notify.error({
                    title: '错误',
                    message: '表头重复'
                });
            }
        },
        addTr(way,index){//插入一行数据
        
            let obj = {};
            // this.tableColumns.forEach(item=>{
            //     obj[item.prop] = Math.floor(Math.random()*100);
            // })
            obj = this.getObj(this.tableColumns,obj);
            console.log('obj',obj);
            if(way=='top'){//在第index行之前插入一行
                this.tableData.splice(index-1,0,obj);
            }else{在第index行之后插入一行
                this.tableData.splice(index,0,obj);
            }
           
           
        },
        getObj(tabs,obj){
            tabs.forEach(item=>{
                if(item.children){
                    this.getObj(item.children,obj);
                }else{
                    obj[item.prop] = Math.floor(Math.random()*100);
                }
            })
            return obj;
        },
        setCurrent(row) {
            this.$refs.singleTable.setCurrentRow(row);
        },
        handleCurrentChange(val) {//点击行事件
            console.log('val',val);
            this.currentRow = val;
        },
    }
}
</script>
<style scoped>
</style>

你可能感兴趣的:(前端,vue,vue.js,javascript,前端,elementui)