1

作为参考,完整的代码可以在这里获取

我有三个选择元素,它们应该在我的页面上充当过滤器,调用该myfilter函数。然后,在一个表中,我使用data-某些<td>元素中的属性对它们进行“分类”,而无需设置不同的类:

<select id="formats" onchange="myfilter('formats', 'mytable')">
  <option value="nofilter">--ALL VALUES--</option>
  <option value="apple">Apples</option>
  <option value="orange">Oranges</option>
  <option value="noattr">Unknown</option>
</select>

<table>
  <tr>
    <td data-format="apple" style="background-color:red;width:10px">&nbsp;</td>
    <td data-model="film" style="background-color:#3ca971;width:10px">&nbsp;</td>
    <td data-type="water" style="background-color:#458985;width:10px">&nbsp;</td>
    <th>1</th>
    <td>Michael</td>
    <td>New York</td>
    <td>M</td>
  </tr>
</table>

myfilter函数改编自W3Schools的示例,检索选定列表框的值,确定它应该查找的列,并将自定义data-属性与值进行比较,以保持行可见或隐藏它们:

function myfilter(myelement, reftable) {
    var input, filter, table, tr, td, i, j, txtValue, rowstyle, checkvisible;
    // Obtains the "value" element of the selected listbox
    input = document.getElementById(myelement);
    filter = input.value;

    table = document.getElementById(reftable);
    tr = table.getElementsByTagName("tr");
    switch(myelement) {
        case "formats":
            j = 0;
            break;
        case "models":
            j = 1;
            break;
        case "types":
            j = 2;
    }
    for (i = 0; i < tr.length; i++) {
        td = tr[i].getElementsByTagName("td")[j];
        if (td) {
            // Retrieves the respective "data-" attribute from <td>
            switch(myelement) {
                case "formats":
                    txtValue = td.dataset.format;
                    break;
                case "models":
                    txtValue = td.dataset.model;
                    break;
                case "types":
                    txtValue = td.dataset.type;
            }
            // If there's no style attribute, it's visibleby default
            rowstyle = tr[i].getAttribute("style");
            if (rowstyle == null) {
                checkvisible = true;
            }
            // If it is hidden, getAttribute returns "display: none;"
            else if (rowstyle.includes("none")) {
                checkvisible = false;
            }
            else {
                checkvisible = true;
            }

            // Maintains or hides the row
            if (filter == "nofilter") {
                tr[i].style.display = "";
            }
            else if ((txtValue == filter) & checkvisible == true) {
                tr[i].style.display = "";
            }
            else {
                tr[i].style.display = "none";
            }
        }
    }
}

问题

操作方式myfilter允许组合过滤器,但需要注意:

  • 在单个过滤器上,必须--ALL VALUES--在选择另一个过滤器之前重置为;
  • 组合过滤器时,上述规则阻止我在另一个过滤器到位时动态切换值。

我必须如何更改 JavaScript 函数才能使组合过滤器按预期工作(例如,像 Excel 过滤器,您保留一个过滤器并更改另一个过滤器)?我曾想过将函数一分为三,但结果却是相同的。

4

1 回答 1

2

通过将数据放在单元格而不是行上,您使事情变得更加复杂。

无论如何,onchange从元素中删除属性<select>并使用它似乎有效:

const table = document.getElementById('mytable');
const filters = [
  ['formats', 'format'],
  ['models', 'model'],
  ['types', 'type'],
];
filters.forEach(v => v[0] = document.getElementById(v[0]));
const rows = Array.from(table.querySelectorAll('tr:not(:first-child)')).map(row => {
  return [row, filters.map(v => row.querySelector(`td[data-${v[1]}]`).dataset[v[1]])];
});
const changeHandler = event => {
  const targets = filters.map(v => v[0].value);
  rows.forEach(row => {
    row[0].style.display = targets.every(
      (v,i) => v == 'nofilter' || v == row[1][i]
    ) ? '' : 'none';
  });
};
filters.forEach(v => {
  v[0].addEventListener('change', changeHandler);
});
changeHandler();

filtersselect是id 和单元格数据名称之间的映射数组。id 被转换为<select>元素引用。

rows是行与其数据之间的映射。这使得执行过滤器更方便。

changeHandler处理<select> change事件。它获取当前<select>值,然后使用它们来确定显示哪些行。

然后我们附加changeHandler到每个<select>元素并触发一次以同步所有内容。

于 2020-11-21T23:48:29.447 回答