使用jQuery合并相同的表格单元格

9

具有NxM值的简单HTML表格。目标是使用jQuery合并列中相同的单元格。请注意,一行中没有重复项。

我知道如何隐藏相同的单元格,但是否有任何方法将带数据的单元格与空单元格组合在一个单元格中?

HTML:

<table border="1" id="testTable">
<tr>
    <td>First</td>
    <td>A</td>
    <td>A</td>
</tr>
<tr>
    <td>First</td>
    <td>A</td>
    <td>B</td>
</tr>
<tr>
    <td>Second</td>
    <td>V</td>
    <td>S</td>
</tr>
<tr>
    <td>Third</td>
    <td>D</td>
    <td>H</td>
</tr>
<tr>
    <td>Third</td>
    <td>E</td>
    <td>E</td>       
</tr>
</table>

JS:

var seenArray = {};
$('#testTable td').each(function() 
{
    var index =  $(this).index();
    var txt = $(this).text();
    if (seenArray[index] === txt) 
    {
        $(this).text(''); //I think here should be "marging"
    }
    else 
    {
        seenArray[index] = txt;
    }
});

jsFiddle

补充说明:还有一件事,数据最初以json数组形式检索,然后我首先使用 .parseJSON() 并将数据放入表格中:

for (var i = 0; i < obj.length; i++) 
{
    tr = $('<tr/>');
    tr.append("<td>" + obj[i]['columnA'] + "</td>");
    tr.append("<td>" + obj[i]['columnB'] + "</td>");
    tr.append("<td>" + obj[i]['columnC'] + "</td>");
    $('#testTable').append(tr); 
}

更新

alFReD NSH 提供了一个适用于 2 个单元格的好方法。他的解决方案在这里。但是,如果有超过 2 个相等的单元格。


那么这里的“First”和“A”应该是一个单元格吗? - Farid Nouri Neshat
请将"First"和下面的空单元格合并。请检查jsfiddle。 - Aleksey Potapov
6个回答

10

如果我理解你的意思,这是我编辑后的版本: http://jsfiddle.net/djhU7/4/

所以,我用了这个代替 $(this).text(''):

    $($this.parent().prev().children()[index]).attr('rowspan', 2);
    $this.hide();

我所做的是将第一个单元格的 rowspan 设置为 2。这个属性“表示单元格延伸的行数”,这将使上面的单元格变大两倍,并隐藏了带有重复信息的单元格,因此额外的单元格将消失。请注意,删除单元格将破坏下一个单元格的索引检查。这只是一个快速而简单的解决方案,但必须在某个地方使用 rowspan 属性才能实现。
这是另一个版本,在将单元格插入表格时设置 rowspan,除了可以处理 3 个或更多个重复单元格之外,它还更快,因为它避免了表格的重新渲染(尽管它可以进一步优化,但我认为此时你不需要关心,过早的优化是万恶之源!):http://jsfiddle.net/g7uY9/1/
for (var i = 0; i < obj.length; i++) {


   tr = $('<tr/>');

    addColumn(tr, 'columnA', i);
    addColumn(tr, 'columnB', i);
    addColumn(tr, 'columnC', i);
    $('#testTable').append(tr);

}

function addColumn(tr, column, i) {
    var row = obj[i],
        prevRow = obj[i - 1],
        td = $('<td>' + row[column] + '</td>');
    if (prevRow && row[column] === prevRow[column]) {
        td.hide();
    } else {
        var rowspan = 1;
        for (var j = i; j < obj.length - 1; j++) {
            if (obj[j][column] === obj[j + 1][column]) {
                rowspan++;
            } else {
                break;
            }
        }
        td.attr('rowspan', rowspan);
    }

    tr.append(td);
}

1
有一个 bug,第二个单元格没有合并,我只是使用 hide 而不是 remove 来修复了它。 - Farid Nouri Neshat
还有一件事,如果有超过2个相等的单元格怎么办? - Aleksey Potapov
1
你可以从最后一行开始,往上处理多于2个相同单元格的情况。 - Greg
@alFReDNSH,现在我正在尝试弄清楚为什么jsfiddle显示错误:“函数声明不应放置在块中”。 - Aleksey Potapov

6
请看我改进后的答案,包含行展开/折叠。这是我的示例代码:
function MergeGridCells()
{
    var dimension_cells = new Array();
    var dimension_col = null;

    var i = 1;
    // First, scan first row of headers for the "Dimensions" column.
    $("#mytable").find('th').each(function () {
        if ($(this).text() == 'Id') {
            dimension_col = i;
        }
        i++;
    });

    // first_instance holds the first instance of identical td
    var first_instance = null;
    var rowspan=1;
    // iterate through rows
    $("#mytable").find('tr.parent-grid-row').each(function () {

        // find the td of the correct column (determined by the dimension_col set above)
        var dimension_td = $(this).find('td.parent-grid-column:nth-child(' + dimension_col + ')');

        if (first_instance == null) {
            // must be the first row
            first_instance = dimension_td;
        } else if (dimension_td.text() == first_instance.text()) {
            // the current td is identical to the previous
            // remove the current td
            dimension_td.remove();
            ++rowspan;
            // increment the rowspan attribute of the first instance
            first_instance.attr('rowspan', rowspan);
        } else {
            // this cell is different from the last
            first_instance = dimension_td;
            rowspan=1;
        }
    });
}

JQuery单元格合并


1
这个简单的任务看起来既酷又复杂。 但是你的+1。 - Aleksey Potapov

4
这是carla的答案的可运行版本:

这里

function SummerizeTable(table) {
  $(table).each(function() {
    $(table).find('td').each(function() {
      var $this = $(this);
      var col = $this.index();
      var html = $this.html();
      var row = $(this).parent()[0].rowIndex; 
      var span = 1;
      var cell_above = $($this.parent().prev().children()[col]);

      // look for cells one above another with the same text
      while (cell_above.html() === html) { // if the text is the same
        span += 1; // increase the span
        cell_above_old = cell_above; // store this cell
        cell_above = $(cell_above.parent().prev().children()[col]); // and go to the next cell above
      }

      // if there are at least two columns with the same value, 
      // set a new span to the first and hide the other
      if (span > 1) {
        // console.log(span);
        $(cell_above_old).attr('rowspan', span);
        $this.hide();
      }
      
    });
  });
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button onclick="SummerizeTable('#table1')">Summerize</button>
<table id="table1" border="1" cellspacing="0" >
  <thead>
    <tr>
      <th>State</th>
      <th>City</th>
      <th>Street</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>VT</td>
      <td>Burlington</td>
      <td>Elm</td>
    </tr>
    <tr>
      <td>NY</td>
      <td>Manhattan</td>
      <td>Main</td>
    </tr>
    <tr>
      <td>NY</td>
      <td>Manhattan</td>
      <td>Oak</td>
    </tr>
    <tr>
      <td>NY</td>
      <td>Albany</td>
      <td>State</td>
    </tr>
  </tbody>
</table>


注意:注释中说“如果文本相同”,但实际上函数比较的是.html()的输出,这可能因为不同的属性、隐藏字段或非文本id而有所不同,这对用户来说应该是透明的。因此,最好像这样比较每个<td>修剪 文本 $.trim($this.text()) - KyleMit

1
我扩展了Carla的解决方案。 通过两个函数,我们可以水平或垂直合并单元格,并排除或包含需要合并的单元格。 试用这个可工作的样例。 https://jsfiddle.net/bn3u63pe
/*
* merge horizontally
* ex) autoMergeByCol('theTable', 2, 0, 0);
*/
function autoMergeByCol(tableId
        , rowStartIndex // zero or positive
        , colStart      // zero or positive
        , colEnd        // equals to colStart or greater than colStart or negative to go to the end of cols
        ) {
    /*
    console.log('autoMergeByCol tableId=' + tableId
        + ', rowStartIndex=' + rowStartIndex
        + ', colStart=' + colStart
        + ', colEnd=' + colEnd
    );
    */
    var trArr = $('#' + tableId).find('tr');        // rows array
    for(var rowIndex = rowStartIndex ; rowIndex < trArr.length ; rowIndex++) {
    var tdArr = $(trArr[rowIndex]).find('td');  // cols array of the row
    if(colEnd < 0) colEnd = tdArr.length - 1;       // if colEnd is negative, process at the end of the cols;
        for(var colIndex = colStart ; colIndex < tdArr.length && colIndex <= colEnd ; colIndex++) {
            var span = 1;
            var theCell = $(tdArr)[colIndex];
            if($(theCell).attr('rowspan')) {continue;}
            var cellNext = $($(theCell).parent().children()[colIndex + span]);      
            while(cellNext != undefined 
                    && $(theCell).text() == $(cellNext).text()
                    && colIndex + span <= colEnd ) {
                span++;
                cellNext.hide();
                cellNext = $($(cellNext).parent().children()[colIndex + span]);     
            }
            if(span > 1) $(theCell).attr('colspan', span);
        }
    }
}

/*
* merge vertically
* ex) autoMergeByCol('theTable', 2, 0, 0);
*/
function autoMergeByRow(tableId
        , rowStartIndex // zero or positive
        , colStart      // zero or positive
        , colEnd        // equals to colStart or greater than colStart or negative
        ) {
    /*
    console.log('autoMergeByRow tableId=' + tableId
        + ', rowStartIndex=' + rowStartIndex
        + ', colStart=' + colStart
        + ', colEnd=' + colEnd
    );
    */
    var trArr = $('#' + tableId).find('tr');            // rows array
    for(var rowIndex = rowStartIndex ; rowIndex < trArr.length ; rowIndex++) {
        var tdArr = $(trArr[rowIndex]).find('td');  // cols array of the row
        if(colEnd < 0) colEnd = tdArr.length - 1;       // if colEnd is negative, process at the end of the cols;
        for(var colIndex = colStart ; colIndex < tdArr.length && colIndex <= colEnd ; colIndex++) {
            var span = 1;
            var theCell = $(tdArr)[colIndex];
            if($(theCell).attr('colspan')) {continue;}
            var cellBelow = $($(theCell).parent().next().children()[colIndex]);         
            while(cellBelow != undefined 
                    && $(theCell).text() == $(cellBelow).text()) {
                span++;
                cellBelow.hide();
                cellBelow = $($(cellBelow).parent().next().children()[colIndex]);           
            }
            if(span > 1) $(theCell).attr('rowspan', span);          
        }
    }
}

1
  $(document).ready(function () {
        SummerizeTable($('#example'));
      })



      function SummerizeTable(table) {
        $(table).each(function () {
          $(table).find('td').each(function () {
            var $this = $(this);
            var col = $this.index();
            var html = $this.html();
            var row = $(this).parent()[0].rowIndex;
            var span = 1;
            var cell_above = $($this.parent().prev().children()[col]);

            while (cell_above.html() === html) { 
              span += 1; 
              cell_above_old = cell_above; 
              cell_above = $(cell_above.parent().prev().children()[col]); 
            }

            if (span > 1) {
              $(cell_above_old).attr('rowspan', span);
              $this.hide();
            }

          });
        });
      }

请看这个工作示例here

1

我非常喜欢Farid的第一种解决方案, 但我需要选择要应用它的行范围和哪些列, 所以我进行了一些修改 (包括更多的单元格合并选项). http://jsfiddle.net/djhU7/72/

function Merge_cells($id_table,$lin_ini,$lin_fim,$array_col=array()){

$colunas="";  
for($k=0;$k<count($array_col);$k++)  $colunas=$colunas . " col =='$array_col[$k]' ||";
if(count($array_col)>0) $colunas="(".substr($colunas,0,-3).") &&";    

echo   "<script>
$('#$id_table td').each(function() 
{
    var \$this = $(this);
    var col = \$this.index();                
    var txt =  \$this.text();                
    var row = $(this).parent()[0].rowIndex; 

    //define the interval of lines and columns it will look at
    if((col==0 || col==1 || col==2) row>=firstRow && row<=lastRow){ 
        span=1;
        cell_above = $(\$this.parent().prev().children()[col]);

        //look for cells one above another with the same text
        while(cell_above.text()=== txt){                    //if the text is the same
            span+=1;                                        //increase the span
            cell_above_old = cell_above;                    //store this cell
            cell_above = $(cell_above.parent().prev().children()[col]);    //and go to the next cell above
        }

        //if there are at least two columns with the same value, set a new span to the first and hide the other
        if(span>1) {
            console.log(span);
            $(cell_above_old).attr('rowspan',span); 
            \$this.hide();
        }              
    }
});

       </script>";
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接