首先技術原理基於狂人論壇的大大yunfengcheng發的帖子《100行代碼解決ExtJs4.1合併單元格問題》,表示感謝。
如果需要他的代碼各位可自行下載,在此不方便貼出(人家可賣30個金錢的呢,雖然有點小貴,呵呵)。
好了,進入正題吧。首先使用他的代碼後效果如下:
從這幅圖可以看出,該合併的都合併了,不該合併的也合併了,第三列“A單元”,屬於不同的地塊,不同棟數,常理是不應該合併的,所以引出一個問題,合併列時應該判斷前一列的合併情況,屬於不同合併區的單元格雖然值相等但不進行合併。效果應該是這樣:
這是優化後的代碼效果,下面說說具體方法:
如果你看了《100行代碼解決ExtJs4.1合併單元格問題》的代碼會發現,其中寫了很多each語句,而且是嵌套的,在實現上圖效果時,已經明顯感覺速度有點慢,所以筆者就奇怪搞這麼多each幹嘛呢?直接用數組多好,參數已經指定合併的列了,用數組直接取不就得啦。
代碼如下:
/**
* Kunoy
* 合併單元格
* @param {} grid 要合併單元格的grid對象
* @param {} cols 要合併哪幾列 [1,2,4]
*/
var mergeCells = function(grid,cols){
var arrayTr=document.getElementById(grid.getId()+"-body").firstChild.firstChild.firstChild.getElementsByTagName('tr');
var trCount = arrayTr.length;
var arrayTd;
var td;
var merge = function(rowspanObj,removeObjs){ //定義合併函數
if(rowspanObj.rowspan != 1){
arrayTd =arrayTr[rowspanObj.tr].getElementsByTagName("td"); //合併行
td=arrayTd[rowspanObj.td-1];
td.rowSpan=rowspanObj.rowspan;
td.vAlign="middle";
Ext.each(removeObjs,function(obj){ //隱身被合併的單元格
arrayTd =arrayTr[obj.tr].getElementsByTagName("td");
arrayTd[obj.td-1].style.display='none';
});
}
};
var rowspanObj = {}; //要進行跨列操作的td對象{tr:1,td:2,rowspan:5}
var removeObjs = []; //要進行刪除的td對象[{tr:2,td:2},{tr:3,td:2}]
var col;
Ext.each(cols,function(colIndex){ //逐列去操作tr
var rowspan = 1;
var divHtml = null;//單元格內的數值
for(var i=1;i<trCount;i++){ //i=0表示表頭等沒用的行
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;
rowspanObj = {tr:i,td:col,rowspan:rowspan}
}else{
var cellText = arrayTd[col-1].innerHTML;
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();
}
}
});
};
另外:
if(colIndex!=cols[0]){
var leftDisplay=arrayTd[col-2].style.display;//判斷左邊單元格值是否已display
if(leftDisplay=='none')
addf();
else
mergef();
}else
addf();
colIndex!=cols[0]是跳過第一列(開始合併的第一列),這一列不需要判斷前一列的合併情況,這裏採用display來做判斷條件,因爲被合併的都是display=none,沒有合併的說明此處是兩個合併區的分隔點,當然你也可以自己寫另外的判斷條件,可以定義一個函數判斷一個單元格是否處於一個合併區裏面,那麼條件就是本單元格的左一個單元格和上左的單元格是否處於同一個合併區,是循環繼續,不是則進行合併,方法很多,各位自由發揮,有了新的方法不防大家交流學習一下。
代碼中註釋的部分是可以不用的:Ext.each(arrayTd,function(Td){ //獲取RowNumber列和check列
if(Td.getAttribute("class").indexOf("x-grid-cell-special") != -1)
cold++;
});
使用方法:
Ext.getCmp('grid').getStore().on('load',function(){
mergeCells(Ext.getCmp('grid'),[1,2,3,4,5,6]);
});
當數據加載完成後執行,從第一列開發合併;如果第一列是RowNumberer列,那麼就用[2,3,4,5,6],跳過第一列即可。
原文:http://blog.csdn.net/kunoy/article/details/7829395