开发者问题收集

尝试使用数组检查字符串来过滤 HTML 表

2022-03-21
160

我正在尝试过滤一个 HTML 表并显示与我的关键字完全匹配的现有行 -

例如。我的 html 表如下

<style type="text/css">
.tg  {border-collapse:collapse;border-spacing:0;}
.tg td{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
  overflow:hidden;padding:10px 5px;word-break:normal;}
.tg th{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
  font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;}
.tg .tg-0pky{border-color:inherit;text-align:left;vertical-align:top}
</style>
<style type="text/css">
.tg  {border-collapse:collapse;border-spacing:0;}
.tg td{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
  overflow:hidden;padding:10px 5px;word-break:normal;}
.tg th{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
  font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;}
.tg .tg-0pky{border-color:inherit;text-align:left;vertical-align:top}
</style>
<table class="tg">
<thead>
  <tr>
    <th class="tg-0pky">ID</th>
    <th class="tg-0pky">Name</th>
    <th class="tg-0pky">Tags</th>
  </tr>
</thead>
<tbody>
  <tr>
    <td class="tg-0pky">1</td>
    <td class="tg-0pky">Test1</td>
    <td class="tg-0pky">AIRPORT TERMINAL,AVIATION,HANGAR,MAINTENANCE BUILDING,NEW CONSTRUCTION,OFFICE</td>
  </tr>
  <tr>
    <td class="tg-0pky">2</td>
    <td class="tg-0pky">Test2</td>
    <td class="tg-0pky">HIGHER EDUCATION,OFFICE,RENOVATION,SCHOOLS - COLLEGE</td>
  </tr>
  <tr>
    <td class="tg-0pky">3</td>
    <td class="tg-0pky">Test3</td>
    <td class="tg-0pky">HIGHER EDUCATION,REMODEL,SCHOOLS - COLLEGE</td>
  </tr>
  <tr>
    <td class="tg-0pky">4</td>
    <td class="tg-0pky">Test4</td>
    <td class="tg-0pky">APARTMENT,HIGHER EDUCATION,NEW CONSTRUCTION,SCHOOLS - COLLEGE</td>
  </tr>
</tbody>
</table>

从这里,我尝试使用 JQuery 或 JavaScript 进行过滤,仅显示包含至少所有特定单词的行。

例如。

如果我发送一个数组

const Keywords = ["HIGHER EDUCATION", "RENOVATION"];

它应该只显示 ID 为 2 的行 如果我发送一个数组

const Keywords = ["HIGHER EDUCATION", "SCHOOLS-COLLEGE"];

它应该显示 ID 为 2 和 3 的行,因为它们都包含这些词,它不应该显示 1 或 4,因为它不包含所有这些词加上额外内容。

我计划使用我目前用来过滤其他项目列的这个 -

 var jo = $("#" + tablename).find("tr:not(:first)");
        jo.filter(function (i, v) {
            var $t = $(this).children(":eq(" + indexColumn + ")");
            for (var d = 0; d < data.length; ++d) {
                if ($t.is(":not(:containsIN('" + data[d] + "'))")) {
                    return true;
                }
            }
            return false;
        }).hide();

我通过获取列索引

  $("#" + tablename).find('th').each(function () {
            if ($(this).find('span').text() == 'tags') {
                d = $(this).index();
                
                var e = $("#" + tablename).find('tr:eq(' + row.index() + ')').find('td:eq(' + d + ')');
              
            }
        });

我希望我说得通这个。

2个回答

在此示例中,我们仅使用 :last-child 来查找标记列。我认为您的问题的关键在于能够根据匹配的字符串或字符串集来过滤行。

<button class="filter" filter="HIGHER EDUCATION,RENOVATION">filter 1</button>

我们稍后将使用此 filter 属性对 split() 进行 ,然后匹配所有整个 filter 并隐藏那些不匹配的。

var filter = $(this).attr("filter").split(",");
  $("table.tg").find("tbody > tr").filter(function(i, r){
    var txt = $(r).find(":last-child").text();  //get the text in the last cell
    var match = filter.every(s=>(new RegExp(s)).test(txt)); //does the text match all the filters?
    return !match;  //if it doesnt match return it to be filtered (hidden)
  }).hide();
$("button.filter").on("click", function(e){
  //show all hidden rows
  $("table.tg").find("tbody > tr").show();
  //split the filter attribute into an array by commas
  var filter = $(this).attr("filter").split(",");
  $("table.tg").find("tbody > tr").filter(function(i, r){
    var txt = $(r).find(":last-child").text();  //get the text in the last cell
    var match = filter.every(s=>(new RegExp(s.trim())).test(txt)); //does the text match all the filters?  trimmed just in-case
    return !match;  //if it doesnt match return it to be filtered (hidden)
  }).hide();
});
<style type="text/css">
.tg  {border-collapse:collapse;border-spacing:0;}
.tg td{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
  overflow:hidden;padding:10px 5px;word-break:normal;}
.tg th{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
  font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;}
.tg .tg-0pky{border-color:inherit;text-align:left;vertical-align:top}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="filter" filter="HIGHER EDUCATION,RENOVATION">filter 1</button>
<button class="filter" filter="HIGHER EDUCATION,SCHOOLS-COLLEGE">filter 2</button>
<button class="filter" filter="">reset</button>
<table class="tg">
<thead>
  <tr>
    <th class="tg-0pky">ID</th>
    <th class="tg-0pky">Name</th>
    <th class="tg-0pky">Tags</th>
  </tr>
</thead>
<tbody>
  <tr>
    <td class="tg-0pky">1</td>
    <td class="tg-0pky">Test1</td>
    <td class="tg-0pky">AIRPORT TERMINAL,AVIATION,HANGAR,MAINTENANCE BUILDING,NEW CONSTRUCTION,OFFICE</td>
  </tr>
  <tr>
    <td class="tg-0pky">2</td>
    <td class="tg-0pky">Test2</td>
    <td class="tg-0pky">HIGHER EDUCATION,OFFICE,RENOVATION,SCHOOLS-COLLEGE</td>
  </tr>
  <tr>
    <td class="tg-0pky">3</td>
    <td class="tg-0pky">Test3</td>
    <td class="tg-0pky">HIGHER EDUCATION,REMODEL,SCHOOLS-COLLEGE</td>
  </tr>
  <tr>
    <td class="tg-0pky">4</td>
    <td class="tg-0pky">Test4</td>
    <td class="tg-0pky">APARTMENT,HIGHER EDUCATION,NEW CONSTRUCTION,SCHOOLS - COLLEGE</td>
  </tr>
</tbody>
</table>
Steve0
2022-03-21

以下示例是不可知的纯 JavaScript 函数。您唯一需要知道的是,特定列中是否存在包含文本的 <table> 。在 OP 中:

// USAGE
const dataArray = tableData('table', 2);
// EITHER
filterTerms(dataArray, "HIGHER EDUCATION", "renovation");
// OR
const keywords = ["HIGHER EDUCATION", "RENOVATION"];
filterTerms(dataArray, keywords)

详细信息在下面的示例中进行了注释
HTML 简洁有效

//Utility function
const log = data => console.log(JSON.stringify(data));

/**
 * Extract text from a given tbody at a given column.
 * @param {string} selector - CSS selector of <table>
 * @param {number} column - index number of <td> within each row that has
 * the text to extract (@default - 0)
 * @returns {array<mixed>} contents of returned array:
 * [DOM Object of <tbody>, [[Strings], [Strings],...]]
 */
const tableData = (selector, column = 0) => {
  // Reference <tbody>
  const T = document.querySelector(selector).tBodies[0];
  /*
  Collect all <tr> in <tbody> into a HTML Collection then convert it into 
  an array
  */// Get qty of rows
  const rows = [...T.rows];
  const rQty = rows.length;
  // Define empty array outside of loop
  let data = [];
  /*
  On each <tr> get the text of the <td> located at the index of @column
  */// Convert text into array and add array to >data<
  for (let r = 0; r < rQty; r++) {
    let tags = rows[r].cells[column].textContent;
    tags = tags.split(/,\s*/);
    data.push(tags);
  }
  //log(data);
  // Return mixed array (see @returns)
  return [T, data];
};

/**
 * Filter a given <table> by completely matching a given string array or 
 * string(s) vs. the data extracted by tableData()
 * All non-matching rows are removed.
 * @param {array<mixed>} tData - (see tableData @returns)
 * @param {array<string> OR string(s)} terms - Strings to search for
 */
const filterTerms = (tData, ...terms) => {
  /*
  Check >terms< is an array or strings.
  If it's an array, flatten it. 
  If it's strings put them in an array.
  */
  //log(terms);
  let keywords = Array.isArray(terms) ?  terms.flat() : [...terms];
  // Ensure strings are uppercase
  const keys = keywords.map(str => str.toUpperCase());
  /*
  >tData< 
  [ tbody, [[text of row 0], [text of row 1],...] ]
  >tData[0]< = tbody
  >tData[1]< = the extracted text of each row at the cell at 
  >column< index
  */
  tData[1].forEach((row, idx) => {
    /*
    Return true if .every() word of >keys< is present in the current 
    array in >tData[1]< If it is true...
    */
    if (keys.every(term => row.includes(term))) {
      //... remove .hide from <tr>..
      tData[0].rows[idx].classList.remove('hide');
    } else {
      // ...otherwise add .hide to <tr> 
      tData[0].rows[idx].classList.add('hide');
    }
  });
};

// Save return of tableData() in a variable
const dataArray = tableData('table', 2);

// Each array is for the second @param
const keywords1 = ["HIGHER EDUCATION", "RENOVATION"];
const keywords2 = ["HIGHER EDUCATION", "SCHOOLS-COLLEGE"];

/*
The second @param >terms< can be an array of strings OR 
one or more strings (see next line)
*/
filterTerms(dataArray, "HIGHER EDUCATION", "renovation");

//filterTerms(dataArray, keywords1);

//filterTerms(dataArray, keywords2);
html {
  font: 2ch/1.15 'Segoe UI';
}

table {
  border-collapse: collapse;
  border-spacing: 0;
  border: black solid 1px;
}

td,
th {
  border: black solid 1px;
  overflow: hidden;
  padding: 10px 5px;
  text-align: left;
  vertical-align: top
}

td:first-of-type {
  text-align: center;
}

.hide {
  display: none;
}
<table><thead><tr><th>ID<th>Name<th>Tags<tbody><tr><td>1<td>Test1<td>AIRPORT TERMINAL,AVIATION,HANGAR,MAINTENANCE BUILDING,NEW CONSTRUCTION,OFFICE<tr><td>2<td>Test2<td>HIGHER EDUCATION,OFFICE,RENOVATION,SCHOOLS-COLLEGE<tr><td>3<td>Test3<td>HIGHER EDUCATION,REMODEL,SCHOOLS-COLLEGE<tr><td>4<td>Test4<td>APARTMENT,HIGHER EDUCATION,NEW CONSTRUCTION,SCHOOLS-COLLEGE</table>
zer00ne
2022-03-22