使用“rowspan”或“colspan”过滤包含合并单元格的表格中的文本

问题描述 投票:0回答:1

我有一个 HTML 代码,我希望

filterTable()
函数在 searchInput 中输入内容后过滤 myTable 表。

例如,如果我输入“Rafael”,相关行应完全显示及其所有合并的单元格,而其余不包含该单词的行应隐藏。

我的代码:

function filterTable() {
    var input = document.getElementById("searchInput");
    var filter = input.value;
    var table = document.getElementById("myTable");
    var rows = table.getElementsByTagName("tr");

    for (var i = 1; i < rows.length; i++) {
        rows[i].style.display = "none";
    }

    for (var i = 1; i < rows.length; i++) {
        var row = rows[i];
        var cells = row.getElementsByTagName("td");
        var rowMatchesFilter = false;

        for (var j = 0; j < cells.length; j++) {
            var cell = cells[j];
            var cellContent = cell.textContent;

            if (cellContent.indexOf(filter) > -1) {
                rowMatchesFilter = true;

                if (cell.getAttribute("rowspan")) {
                    var rowspan = parseInt(cell.getAttribute("rowspan"));
                    for (var k = 0; k < rowspan; k++) {
                        rows[i + k].style.display = "";
                    }
                } else {
                    row.style.display = "";
                }
                break;
            }
        }
        if (rowMatchesFilter) {
            row.style.display = "";
        }
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Table Search</title>
    <style>
        table, th, td {
            border: 1px solid black;
            border-collapse: collapse;
            padding: 8px;
            width: 500px;
        }
    </style>
</head>
<body>

<h2>Information Table</h2>

<input type="text" id="searchInput" placeholder="Enter search text" oninput="filterTable()">

<table id="myTable">
    <thead>
        <tr>
            <th>Building</th>
            <th>Floor</th>
            <th>Name</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td rowspan="5">Building 1</td>
            <td rowspan="2">Floor 1</td>
            <td>Martin</td>
        </tr>
        <tr>
            <td>Cristiano</td>
        </tr>
        <tr>
            <td rowspan="3">Floor 2</td>
            <td>Karim</td>
        </tr>
        <tr>
            <td>Rafael</td>
        </tr>
        <tr>
            <td>Anna</td>
        </tr>
        <tr>
            <td>Building 2</td>
            <td>Floor 1</td>
            <td>Carlos</td>
        </tr>
    </tbody>
</table>
</body>
</html>

但是,当我输入“Rafael”时,它会过滤,但显示:

建筑 地板 姓名
拉斐尔

但我想表明:

建筑 地板 姓名
1号楼 2楼 拉斐尔
javascript html html-table
1个回答
0
投票

我会使用不同的策略,通过使用碰撞检测:)

  • 过滤与搜索字符串匹配的TD
  • 创建一个区域数组,其中 x 和 width 是父 TD 的 TR 元素矩形,y 和 height 是该元素的 x 和高度(因为使用 rowspan 时比 TR 更高)
  • 一旦您拥有这些区域,就可以创建与这些区域发生碰撞的独特
    Set()
    或 TD 元素
  • 过滤那组独特的单元格

// DOM utility functions:
const el = (sel, par = document) => par.querySelector(sel);
const els = (sel, par = document) => par.querySelectorAll(sel);

// Utils
const regEsc = (v) => v.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
const collides = (a, b) =>  a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y;

// Task: Filter table
const elSearch = el("#searchInput");
const elTbody = el("#myTable");
     
const filterTable = (value) => {
  const val = elSearch.value.trim();
  const elsTd = els("td", elTbody);
  const reg = new RegExp(regEsc(val), "i");
  const matchTd = [...elsTd].filter(elTd => reg.test(elTd.textContent));  
  const areas = matchTd.map((elTd) => {
    const elTr = elTd.closest("tr");
    const trBCR = elTr.getBoundingClientRect();
    const tdBCR = elTd.getBoundingClientRect();
    return {
      x: trBCR.x,
      y: tdBCR.y,
      width: trBCR.width,
      height: tdBCR.height,
    }
  });
  
  const filteredTds = areas.reduce((acc, area) => {
    elsTd.forEach((elTd) => collides(area, elTd.getBoundingClientRect()) && acc.add(elTd));
    return acc;
  }, new Set());
  
  elsTd.forEach(elTd => {
    elTd.classList.toggle("hidden", val.length && !filteredTds.has(elTd));
  });
};

elSearch.addEventListener("input", filterTable);
table {
  inline-size: 100%;
  border-collapse: collapse;
  th,
  td {
    border: 1px solid black;
    .hidden {
      display: none;
    }
  }
}
<input type="text" id="searchInput" autocomplete=off placeholder="Search...">

<table id="myTable">
  <thead>
    <tr><th>Building</th><th>Floor</th><th>Name</th></tr>
  </thead>
  <tbody>
    <tr><td rowspan="5">Building 1</td><td rowspan="2">Floor 1</td><td>Martin</td></tr>
    <tr><td>Cristiano</td></tr>
    <tr><td rowspan="3">Floor 2</td><td>Karim</td></tr>
    <tr><td>Rafael</td></tr>
    <tr><td>Anna</td></tr>
    <tr><td>Building 2</td><td>Floor 1</td><td>Carlos</td></tr>
</table>

© www.soinside.com 2019 - 2024. All rights reserved.