SOURCE

/**
* @param {} grid  要合并单元格的grid对象 
* @param {} cols  要合并哪几列 例如 [1,2] 
*/
var mergeCells = function (grid, cols) {
    //==>ExtJs4.2的<tbody>改到上层<table>的lastChild . <tbody>是各个<tr>的集合
    var arrayTr = document.getElementById(grid.getId() + "-body").firstChild.firstChild.lastChild.getElementsByTagName('tr');
    var trCount = arrayTr.length;  //<tr>总行数
    var arrayTd;
    var td;

    //==>显示层将目标格的样式改为.display='none';      
    var merge = function (rowspanObj, removeObjs)//定义合并函数  
    {
        if (0 != rowspanObj.rowspan) {
            arrayTd = arrayTr[rowspanObj.tr].getElementsByTagName("td"); //合并行  
            td = arrayTd[rowspanObj.td - 1];
            td.rowSpan = rowspanObj.rowspan;
            td.vAlign = "middle";
            //    td.style.font-size = '20px';
            //    $(td).hide();
            $(td).css("font-size", "15px");
            $(td).attr("title", $(td).text());
            $(td).find('span').attr("title", $(td).text());
            $(td).css('color', 'rgb(148, 201, 36)');
            var height = $(td).innerHeight();
            if (removeObjs.length > 0) {
                $(td).css("padding-top", height / 3);
                //	var showIndex = Math.ceil(removeObjs.length/2);
            }

            //隐身被合并的单元格  
            Ext.each(removeObjs, function (obj) {
                arrayTd = arrayTr[obj.tr].getElementsByTagName("td");
                arrayTd[obj.td - 1].style.display = 'none';
                arrayTd[obj.td - 1].style.borderTop = "none";
            });

        }
    };
    //==>显示层将目标格的样式改为.display='none';     

    var rowspanObj = {}; //要进行跨列操作的td对象{tr:1,td:2,rowspan:5}      
    var removeObjs = []; //要进行删除的td对象[{tr:2,td:2},{tr:3,td:2}]  
    var col;
    //==>逐列靠表内具体数值去合并各个<tr> (表内数值一样则合并) 

    try {
        Ext.each(cols, function (colIndex) {
            var rowspan = 1;
            var divHtml = null;//单元格内的数值          
            for (var i = 0; i < trCount; i++)//==>从第一行数据0开始
            {
                //==>一个arrayTr[i]是一整行的所有数据, 一个arrayTd是 <td xxxx ><div>具体数值</div></td> ,
                arrayTd = arrayTr[i].getElementsByTagName("td");
                var cold = 0;
                //          Ext.each(arrayTd,function(Td){ //获取RowNumber列和check列  
                //              if(Td.getAttribute("class").indexOf("x-grid-cell-special") != -1)  
                //                  cold++;                               
                //          });  
                col = colIndex + cold;//跳过RowNumber列和check列  

                if (!divHtml) {
                    divHtml = arrayTd[col - 1].innerHTML;
                    divHtml = $(divHtml).text(); //==>拿到真正数值,相比Ext4.1多了一层<div>
                    rowspanObj = { tr: i, td: col, rowspan: rowspan }
                }
                else {
                    var cellText = arrayTd[col - 1].innerHTML;
                    cellText = $(cellText).text();//==>拿到真正数值 


                    var addf = function () {
                        rowspanObj["rowspan"] = rowspanObj["rowspan"] + 1;
                        removeObjs.push({ tr: i, td: col });
                        if (i == trCount - 1) {
                            merge(rowspanObj, removeObjs);//执行合并函数  
                        }
                    };
                    var mergef = function () {
                        merge(rowspanObj, removeObjs);//执行合并函数  
                        divHtml = cellText;
                        rowspanObj = { tr: i, td: col, rowspan: rowspan }
                        removeObjs = [];
                    };

                    if (cellText == divHtml) {
                        if (colIndex != cols[0]) {
                            var leftDisplay = arrayTd[col - 2].style.display;//判断左边单元格值是否已display  
                            if (leftDisplay == 'none') {
                                addf();
                            }
                            else {
                                mergef();
                            }
                        }
                        else {
                            addf();
                        }
                    }
                    else {
                        mergef();
                    }
                }
            }
        });
    } catch (e) {
        console.log(e.message)
    }
};




Ext.onReady(function () {

    var store = Ext.create('Ext.data.Store', {
        storeId: 'myStore',
        autoLoad: false,
        fields: ['firstClass', 'secondClass'],
        data: {
            'items':
                [{
                    firstClass: '正极材料',
                    secondClass: '镍钴锰酸锂'
                }, {
                    firstClass: '正极材料',
                    secondClass: '锰酸锂'
                }, {
                    firstClass: '负极材料',
                    secondClass: '石墨'
                }, {
                    firstClass: '负极材料',
                    secondClass: '六弗锰酸锂'
                }]
        },
        proxy: {
            type: 'memory',
            reader: {
                type: 'json',
                root: 'items'
            }
        }
    });

    var grid = Ext.create('Ext.grid.Panel', {
        renderTo: Ext.getBody(),
        selType: 'cellmodel',
        /*tbar: [{
            text: '单元格合并',
            handler: function () {
                mergeCells(grid, [1]);
            }
        }],*/
        id: 'mygrid',
        columns: [{
            text: '一级分类',
            dataIndex: 'firstClass'
        }, {
            text: '二级分类',
            dataIndex: 'secondClass'
        }],
        store: store
    });

    setTimeout(function(){
        mergeCells(grid, [1]);
    },100)
    /* grid.getStore().load(function(){
         alert('1');
         mergeCells(grid, [1]);
     });*/
});
console 命令行工具 X clear

                    
>
console