使用JavaScript合并表格行

时间:2019-02-08 11:11:09

标签: javascript html css

我使用的是普通表,这是我的要求:

如果一个表的行值重复,则应使用javascript合并。例如:表1的行值和table2的行值相同,则应将其合并,并且该值只能使用javascript显示一次。在这里,我将附上我的编码。

function myFunction() {
  const firstRows = { };
  let shade = false;
  
  const colsToMerge = [0, 1];

  Array.from(document.querySelectorAll('tbody tr')).forEach(tr => {
    const text = tr.children[0].innerText;
    if (!(text in firstRows)) {
      firstRows[text] = { shade, elem: tr, count: 1 };
      shade = !shade;
    } else {
      const firstRow = firstRows[text]
      firstRow.count++;
      colsToMerge.forEach(i => tr.children[i].remove());
      colsToMerge.forEach(i =>
        firstRow.elem.children[i]
                .setAttribute('rowspan', firstRow.count)
      );
    }
    if (firstRows[text].shade) tr.classList.add('dark');
  });
}
table {
  font-family: arial, sans-serif;
  border-collapse: collapse;
  width: 100%;
}

th {
  background: #a9a9a9;
}

td,
th {
  border: 1px solid #dddddd;
  text-align: center;
  padding: 8px;
  font-family: monospace;
  font-size: 17px;
}

.dark {
  background-color: #dddddd;
}
<body onload="myFunction()">
  <table>
    <tr>
      <th>Company</th>
      <th>Contact</th>
      <th>Country</th>
    </tr>
    <tbody>
      <tr>
        <td>Alfreds Futterkiste</td>
        <td>Maria Anders</td>
        <td>Germanyindgo</td>
      </tr>
      <tr>
        <td>Alfreds Futterkiste</td>
        <td>Maria Anders</td>
        <td>Germany</td>
      </tr>
      <tr>
        <td>Centro comercial Moctezuma</td>
        <td>Francisco Chang</td>
        <td>Mexico</td>
      </tr>
      <tr>
        <td>Ernst Handel</td>
        <td>Roland Mendel</td>
        <td>Austria</td>
      </tr>
      <tr>
        <td>Island Trading</td>
        <td>Helen Bennett</td>
        <td>UK</td>
      </tr>
      <tr>
        <td>Laughing Bacchus Winecellars</td>
        <td>Yoshi Tannamuri</td>
        <td>Canada</td>
      </tr>
      <tr>
        <td>Magazzini Alimentari Riuniti</td>
        <td>Giovanni Rovelli</td>
        <td>Italy</td>
      </tr>
    </tbody>
  </table>
</body>

Check this table

3 个答案:

答案 0 :(得分:2)

这是用于动态合并每列中的连续行单元格的有效解决方案。

该解决方案还用于切换阴影,并且仅在“满”行开始时(即连续的行之间没有合并时)才切换阴影。

此外,您还必须将tr包装在表头中的thead中,因为这可能导致在查询中指定document.querySelectorAll('tbody tr')事件tbody时出现问题。 / p>

我稍微修改了表格以显示阴影和合并: enter image description here

function myFunction() {
  const previousRow = {};
  const colsChanged = {};
  let dark = false;

  Array.from(document.querySelectorAll('tbody tr')).forEach((tr, rowIdx) => {
    Array.from(tr.children).forEach((td, colIdx) => {
      if (rowIdx > 0 && previousRow[colIdx].text === td.innerText) {
        previousRow[colIdx].elem.setAttribute('rowspan', ++previousRow[colIdx].span);
        colsChanged[colIdx] = false;
        td.remove();
      } else {
        previousRow[colIdx] = { span: 1, text: td.innerText, elem: td, dark };
        colsChanged[colIdx] = true;
      }
    });
    const rowChanged = Object.values(colsChanged).every(Boolean);
    dark = rowChanged && rowIdx > 0 ? !dark : dark;
    if (dark) {
      tr.classList.add('dark');
    }
  });
}
table {
  font-family: arial, sans-serif;
  border-collapse: collapse;
  width: 100%;
}

th {
  background: #a9a9a9;
}

td,
th {
  border: 1px solid black;
  text-align: center;
  padding: 8px;
  font-family: monospace;
  font-size: 17px;
}

.dark {
  background-color: #dddddd;
}
<body onload="myFunction()">
  <table>
    <thead>
      <tr>
        <th>Company</th>
        <th>Contact</th>
        <th>Country</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Alfreds Futterkiste</td>
        <td>Maria Anders</td>
        <td>Germanyindgo</td>
      </tr>
      <tr>
        <td>Alfreds Futterkiste</td>
        <td>Maria Anders</td>
        <td>Germany</td>
      </tr>
      <tr>
        <td>Centro comercial Moctezuma</td>
        <td>Francisco Chang</td>
        <td>Mexico</td>
      </tr>
      <tr>
        <td>Ernst Handel</td>
        <td>Francisco Chang</td>
        <td>Austria</td>
      </tr>
      <tr>
        <td>Ernst Handel</td>
        <td>Helen Bennett</td>
        <td>UK</td>
      </tr>
      <tr>
        <td>Laughing Bacchus Winecellars</td>
        <td>Yoshi Tannamuri</td>
        <td>Canada</td>
      </tr>
      <tr>
        <td>Magazzini Alimentari Riuniti 1</td>
        <td>Giovanni Rovelli 1</td>
        <td>Italy</td>
      </tr>
      <tr>
        <td>Magazzini Alimentari Riuniti 2</td>
        <td>Giovanni Rovelli 2</td>
        <td>Italy</td>
      </tr>
      <tr>
        <td>Magazzini Alimentari Riuniti 3</td>
        <td>Giovanni Rovelli 3</td>
        <td>Italy</td>
      </tr>
    </tbody>
  </table>
</body>

根据下面的注释,如果仅在第一列中合并了相应的单元格的情况下才想在右侧合并单元格,请执行以下修改。

一个leftMerged变量用于跟踪当前行上的第一个单元格是否已合并到前一个单元格,如果是这样,这使我们能够在必要时将后面的单元格合并到右侧。在每一行的开头将该变量重置为false。

enter image description here

function myFunction() {
  const previousRow = {};
  const colsChanged = {};
  let leftMerged = false;
  let dark = false;

  Array.from(document.querySelectorAll('tbody tr')).forEach((tr, rowIdx) => {
    Array.from(tr.children).forEach((td, colIdx) => {
      if (rowIdx > 0 && (colIdx === 0 || leftMerged) && previousRow[colIdx].text === td.innerText) {
        previousRow[colIdx].elem.setAttribute('rowspan', ++previousRow[colIdx].span);
        colsChanged[colIdx] = false;
        td.remove();
        if (colIdx === 0) {
          leftMerged = true;
        }
      } else {
        previousRow[colIdx] = { span: 1, text: td.innerText, elem: td, dark };
        colsChanged[colIdx] = true;
      }
    });
    const rowChanged = Object.values(colsChanged).every(Boolean);
    dark = rowChanged && rowIdx > 0 ? !dark : dark;
    if (dark) {
      tr.classList.add('dark');
    }
    leftMerged = false;
  });
}
table {
  font-family: arial, sans-serif;
  border-collapse: collapse;
  width: 100%;
}

th {
  background: #a9a9a9;
}

td,
th {
  border: 1px solid black;
  text-align: center;
  padding: 8px;
  font-family: monospace;
  font-size: 17px;
}

.dark {
  background-color: #dddddd;
}
<body onload="myFunction()">
  <table>
    <thead>
      <tr>
        <th>Company</th>
        <th>Contact</th>
        <th>Country</th>
        <th>Col4</th>
        <th>Col5</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Alfreds Futterkiste</td>
        <td>Maria Anders</td>
        <td>Germanyindgo</td>
        <td>1</td>
        <td>2</td>
      </tr>
      <tr>
        <td>Alfreds Futterkiste</td>
        <td>Maria Anders</td>
        <td>Germany</td>
        <td>1</td>
        <td>2</td>
      </tr>
      <tr>
        <td>Centro comercial Moctezuma</td>
        <td>Francisco Chang</td>
        <td>Mexico</td>
        <td>1</td>
        <td>2</td>
      </tr>
      <tr>
        <td>Ernst Handel</td>
        <td>Francisco Chang</td>
        <td>Austria</td>
        <td>1</td>
        <td>2</td>
      </tr>
      <tr>
        <td>Ernst Handel</td>
        <td>Helen Bennett</td>
        <td>UK</td>
        <td>1</td>
        <td>2</td>
      </tr>
      <tr>
        <td>Laughing Bacchus Winecellars</td>
        <td>Yoshi Tannamuri</td>
        <td>Canada</td>
        <td>1</td>
        <td>2</td>
      </tr>
      <tr>
        <td>Magazzini Alimentari Riuniti 1</td>
        <td>Giovanni Rovelli 1</td>
        <td>Italy</td>
        <td>1</td>
        <td>2</td>
      </tr>
      <tr>
        <td>Magazzini Alimentari Riuniti 1</td>
        <td>Giovanni Rovelli 2</td>
        <td>Italy</td>
        <td>1</td>
        <td>2</td>
      </tr>
      <tr>
        <td>Magazzini Alimentari Riuniti 3</td>
        <td>Giovanni Rovelli 3</td>
        <td>Italy</td>
        <td>1</td>
        <td>2</td>
      </tr>
    </tbody>
  </table>
</body>

答案 1 :(得分:1)

您可以使用Javascript动态地执行此操作。检查这个小提琴:

let previousObj = [];
const rows = $("table tr");
rows.each(function(i, el) {
    let obj = [];
    $(el).children("td").each(function(ic, elc) {
    obj.push(elc);

    if (previousObj.length > ic) {
        if (previousObj[ic].innerHTML == obj[ic].innerHTML) {
        $(previousObj[ic]).attr('rowspan', getRowsSpan(ic, i, obj[ic].innerHTML));
        $(obj[ic]).remove();
      }      
    }
  });

  previousObj = obj;
});

function getRowsSpan(col, row, value) {
    var rowSpan = 2;
  var actualRow = row+1;

  while ($(rows[actualRow]).children("td")[col].innerHTML == value) {
    rowSpan++;
    actualRow++;
  } 

  return rowSpan;
}

https://jsfiddle.net/9e1bcprx/2/

答案 2 :(得分:1)

在下面的代码段中,我首先将数据从表读取到js数组,然后合并具有相似第一列的行,并生成表主体的新html内容

let readTable = (tbody) => [...tbody.rows].map(row=>[...row.cells].map(c=>c.innerText));    

function mergeRows(data) {
  let h={};
  data.forEach((r,i)=> { // merge by first column
      let p=h[r[0]];
      if(p) { p[1].push(r[1]); p[2].push(r[2]) };
      if(!p) { h[r[0]]=[r[0],[r[1]],[r[2]],i]}         
  });     
  let result=Object.values(h).sort((a,b)=>a[3]-b[3]);  
  result.forEach(r=> {r[1]=[... new Set(r[1])]; r[2]=[... new Set(r[2])]}); // remove duplicates in seconond and third column
  return result;
}

function genTable(rows, tbody) {    
  let b="",x="";
  rows.forEach(r=> {
    x=r.map((c,i) => `<td>${c}</td>`).slice(0,3);
    b+=`<tr>${x.join('')}</tr>`;
  })
  tbody.innerHTML=b;
  console.log({b,rows, tbody});
}

function myFunction() {
  let table=document.querySelector('table');
  let tbody=table.tBodies[table.tBodies.length-1]; 
  genTable( mergeRows(readTable(tbody)), tbody );
}
table {
  font-family: arial, sans-serif;
  border-collapse: collapse;
  width: 100%;
}

th {
  background: #a9a9a9;
}

td,
th {
  border: 1px solid #dddddd;
  text-align: center;
  padding: 8px;
  font-family: monospace;
  font-size: 17px;
}

.dark {
  background-color: #dddddd;
}
<body onload="myFunction()">
  <table>
    <tr>
      <th>Company</th>
      <th>Contact</th>
      <th>Country</th>
    </tr>
    <tbody>
      <tr>
        <td>Alfreds Futterkiste</td>
        <td>Maria Anders</td>
        <td>Germanyindgo</td>
      </tr>
      <tr>
        <td>Alfreds Futterkiste</td>
        <td>Maria Anders</td>
        <td>Germany</td>
      </tr>
      <tr>
        <td>Centro comercial Moctezuma</td>
        <td>Francisco Chang</td>
        <td>Mexico</td>
      </tr>
      <tr>
        <td>Ernst Handel</td>
        <td>Roland Mendel</td>
        <td>Austria</td>
      </tr>
      <tr>
        <td>Island Trading</td>
        <td>Helen Bennett</td>
        <td>UK</td>
      </tr>
      <tr>
        <td>Laughing Bacchus Winecellars</td>
        <td>Yoshi Tannamuri</td>
        <td>Canada</td>
      </tr>
      <tr>
        <td>Magazzini Alimentari Riuniti</td>
        <td>Giovanni Rovelli</td>
        <td>Italy</td>
      </tr>
    </tbody>
  </table>
</body>