【问题标题】:Sort table based on cell background color by clicking table header通过单击表格标题根据单元格背景颜色对表格进行排序
【发布时间】:2019-03-28 06:29:28
【问题描述】:

我有一个表格,单元格可以放在其中:

  1. 没有背景颜色
  2. RGB(255, 0, 0)
  3. rgb(255, 165, 0)
  4. RGB(0, 128, 0)

这是我正在谈论的表格的一小部分:

<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">

<table class="w3-table-all">

<tr><th class="w3-center" style="width: 16.7%;">Name</th><th class="w3-center" style="width: 16.7%;">Run-1</th><th class="w3-center" style="width: 16.7%;">Run-2</th><th class="w3-center" style="width: 16.7%;">Run-3</th><th class="w3-center" style="width: 16.7%;">Run-4</th><th class="w3-center" style="width: 16.7%;">Run-5</th></tr>

<tr><th>test1</th><td>9130.47</td><td>392478.721</td><td class="w3-center">-</td><td>44301.148</td><td>44301.148</td></tr>

<tr><th>test2</th><td>747505.0087</td><td style="background: rgb(0, 128, 0);">368460.1843</td><td style="background: rgb(0, 128, 0);">64204.7407</td><td style="background: rgb(0, 128, 0);">106400.8238</td><td style="background: rgb(0, 128, 0);">106400.8238</td></tr>

<tr><th>test3</th><td>65.01%</td><td style="background: rgb(255, 0, 0);">68.25%</td><td style="background: rgb(255, 0, 0);">69.17%</td><td style="background: rgb(255, 0, 0);">65.07%</td><td style="background: rgb(0, 128, 0);">65.07%</td></tr>

<tr><th>test4</th><td>67.53%</td><td>82.72%</td><td>69.67%</td><td>74.29%</td><td>74.29%</td></tr>

<tr><th>test5</th><td>-1906.877</td><td style="background: rgb(0, 128, 0);">-103.597</td><td style="background: rgb(0, 128, 0);">-87.119</td><td style="background: rgb(0, 128, 0);">-132.043</td><td style="background: rgb(0, 128, 0);">-132.043</td></tr>

<tr><th>test6</th><td>64.86%</td><td style="background: rgb(255, 0, 0);">68.09%</td><td style="background: rgb(255, 0, 0);">72.67%</td><td style="background: rgb(255, 165, 0);">65.56%</td><td style="background: rgb(255, 165, 0);">65.56%</td></tr>
</table>

我想通过单击任何标题对表格进行排序,它将根据该特定列中单元格的颜色对其进行排序。例如,当你点击“Run-4”时,我想按如下方式对表格进行排序:

  1. 先红细胞
  2. 橙色
  3. 绿色
  4. 没有颜色

当我再次单击“Run-4”时,它会执行相反的操作:

  1. 先无颜色
  2. 绿色
  3. 橙色
  4. 红色

我尝试引用几个 SO 问题,但没有成功实施:

【问题讨论】:

  • 我明白了,但我不明白你想要排序的顺序,例如在run-2中单击时会发生什么?为什么在 run-4 中使用这种排序顺序?
  • 当您单击 Run-2 时,应该会发生相同的排序。我只是提供了 Run-4 作为示例,因为它包含 &lt;td&gt;,所有 3 种颜色都没有颜色
  • 因此,与单击的“运行”无关,它应该将整个表格从无颜色排序为红色,反之亦然,是吗?你有一些你已经尝试在你的问题中发布的 JS 吗?
  • 另外,这个表是动态创建的吗?它以某种格式出现,如 json、对象或数组?或者它是静态的,直接在 HTML 中创建?
  • 您可以创建一个带有排序键和颜色值的对象并对其进行排序。

标签: javascript jquery html css


【解决方案1】:

操作 DOM 中已有的表

通常,您会将所有表格条目放在一个数据结构中,并根据该结构绘制表格。对表格进行排序会容易得多,因为您只需要对结构进行排序并从中更新表格。

话虽如此,下面介绍了如何从 DOM 中已经存在的表中提取信息并对其进行排序。

您首先需要获取相关的行标题单元格并添加一个点击事件监听器。

var table = document.getElementsByTagName("table")[0],
    rows = table.getElementsByTagName("tr"),
    headers = rows.item(0).getElementsByTagName("th"),
    i, sortOrder = 0;
// start from header 1 not 0 to avoid adding a click
// on the Name header
for ( i=1; i<headers.length; i++ ) {
    headers.item( i ).addEventListener( "click", function() {
        ...
    }
}

在该函数中,您需要做一些事情:

  1. 获取当前列的索引,然后遍历该列中的每个单元格。

  2. 通过单元格检查红色背景。如果单元格的背景为红色,则将其行克隆到已排序的数组中。

  3. 检查单元格是否为绿色,如果它有绿色背景,则将其行克隆到已排序的数组中。

  4. 检查橙色,如果是,yada yada yada。

  5. 检查无背景。在我的代码中,我检查了 style 参数的缺失,该参数适用于这种特定场景。但是,如果任何单元格没有背景但有一些内联样式,那么它们将不会被排序。

  6. 将表格的行替换为已排序的行。

window.onload = function() {
    var table = document.getElementsByTagName("table")[0],
        rows = table.getElementsByTagName("tr"),
        headers = rows.item(0).getElementsByTagName("th"),
        i, sortOrder = 0;
    // start from header 1 not 0 to avoid adding a click
    // on the Name header
    for ( i=1; i<headers.length; i++ ) {
        headers.item( i ).addEventListener( "click", function() {
            // Get the index of the header within its row.
            // This is the same as the column number we'll
            // be editing
            var index = Array.prototype.indexOf.call( this.parentNode.children, this ),
                sortKey = [ "rgb(255,0,0)", "rgb(255,165,0)", "rgb(0,128,0)", "" ],
                sorted = [],
                s, j;
            // initialise static variable for each click function
            // and increment with each click. If it is even
            // then sort normally, if odd then reverse the sort
            if ( !this.sortOrder ) this.sortOrder = 0;
            if ( this.sortOrder % 2 ) sortKey = sortKey.reverse();
            this.sortOrder++;
            // For each background colour...
            for ( s = 0; s < sortKey.length; s++ ) {
                // in each cell in the column...
                for ( j = 1; j < rows.length; j++ ) {
                    var cell = rows.item(j).children[ index ];
                    if ( sortKey[s] == "" ) {
                        // If we're on the last sort key..
                        // and there's no style (so considered
                        // a match) then deep clone into the
                        // sorted array
                        if (cell.outerHTML.indexOf("style") == -1) {
                            sorted.push(rows.item(j).cloneNode(true));
                        }
                    } else if ( cell.outerHTML.replace(/ /g,'').indexOf(sortKey[s]) != -1) {
                        // If background matches...
                        // clone the node into the sorted array.
                        // Use deep cloning to copy content
                        sorted.push(rows.item(j).cloneNode(true));
                    }
                }
            }
            for ( j = 1; j < rows.length; j++ ) {
                rows.item(j).parentNode.replaceChild( sorted[j-1], rows.item(j) );
            }
            
        }, false );
    }
}
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">

<table class="w3-table-all">

<tr><th class="w3-center" style="width: 16.7%;">Name</th><th class="w3-center" style="width: 16.7%;">Run-1</th><th class="w3-center" style="width: 16.7%;">Run-2</th><th class="w3-center" style="width: 16.7%;">Run-3</th><th class="w3-center" style="width: 16.7%;">Run-4</th><th class="w3-center" style="width: 16.7%;">Run-5</th></tr>

<tr><th>test1</th><td>9130.47</td><td>392478.721</td><td class="w3-center">-</td><td>44301.148</td><td>44301.148</td></tr>

<tr><th>test2</th><td>747505.0087</td><td style="background: rgb(0, 128, 0);">368460.1843</td><td style="background: rgb(0, 128, 0);">64204.7407</td><td style="background: rgb(0, 128, 0);">106400.8238</td><td style="background: rgb(0, 128, 0);">106400.8238</td></tr>

<tr><th>test3</th><td>65.01%</td><td style="background: rgb(255, 0, 0);">68.25%</td><td style="background: rgb(255, 0, 0);">69.17%</td><td style="background: rgb(255, 0, 0);">65.07%</td><td style="background: rgb(0, 128, 0);">65.07%</td></tr>

<tr><th>test4</th><td>67.53%</td><td>82.72%</td><td>69.67%</td><td>74.29%</td><td>74.29%</td></tr>

<tr><th>test5</th><td>-1906.877</td><td style="background: rgb(0, 128, 0);">-103.597</td><td style="background: rgb(0, 128, 0);">-87.119</td><td style="background: rgb(0, 128, 0);">-132.043</td><td style="background: rgb(0, 128, 0);">-132.043</td></tr>

<tr><th>test6</th><td>64.86%</td><td style="background: rgb(255, 0, 0);">68.09%</td><td style="background: rgb(255, 0, 0);">72.67%</td><td style="background: rgb(255, 165, 0);">65.56%</td><td style="background: rgb(255, 165, 0);">65.56%</td></tr>
</table>

还实现了反向排序。每个点击函数都附加一个变量,每次点击都会增加一个变量。如果是偶数则正常执行搜索,如果奇数则反向执行搜索。多次单击排序不同的列时,此方法可能会导致一些意外行为。

从抽象结构构建表格

目前您的表格已经存在于 DOM 中。您正在修改其 DOM 结构以按颜色排序;也就是说,您想在已经存在的trs 周围随机播放。一种更有效的方法是让您的表格存在于一种抽象的数据结构中,从该结构中可以绘制表格。需要对数据结构进行任何排序,并且 DOM 中的表将简单地从该结构更新。

包含背景颜色和单元格值的数据结构的简单示例可以用二维数组表示:

[ [ {bg: "", value: "9130.47"},     {bg: "", value: "392478.721"},                {bg: "", value: "-"},                        {bg: "", value: "44301.148"}, ... ],
  [ {bg: "", value: "747505.0087"}, {bg: "rgb(0, 128, 0)", value: "368460.1843"}, {bg: "rgb(0, 128, 0)", value: "64204.7407"}, {bg: "rgb(0, 128, 0)", value: "106400.8238"}, ... ],
  ...
]

然后填充表格将是两个嵌套的for 循环以将单元格添加到其适当位置的简单问题。您可以将此代码放在一个单独的函数中,以便在您更改数据结构的顺序时调用它。

与通过修改当前 DOM 结构进行排序相比,此解决方案通常更健壮、更高效、具有更好的可维护性并且允许以编程方式将新条目添加到表中。

【讨论】:

  • 哇,这看起来可能是我需要的东西。然而,我马上注意到的是它对它们进行水平排序,即通过单击“test1”、“test2”等。但是,我想单击“Run-1”、“Run-2”等。我在我的问题。您能否更新您的答案以便它可以做到这一点?
  • @tera_789 更新了对列而非行进行排序的答案。如果排序后没有变化,我还添加了一个检查来反转列顺序。
  • 完美。我想我们正在接近。我明天也会继续努力,一定会让你知道进展如何。目前,我可以看到排序运行良好,但是,数据显示错误。即,列“名称”没有改变。例如,“test-6”的数据在排序后显示为“test-2”。
  • 另外,如果表已经存在于某些数据结构中会更容易做,这是什么意思?什么样的结构?
  • @tera_789 无论您使用let 还是var,您创建的对象都有一个自动 生命周期和范围,绑定到它们的包含函数。也就是说,它只会在该函数中保持活动状态,并在函数返回时被垃圾收集器删除。在函数完成后仍然存在的变量称为静态变量。 JavaScript 并没有真正的静态变量,但是您可以使用上面使用的对象属性或函数闭包来模拟它们。 stackoverflow.com/questions/48923021/… 详细介绍了一些选项。
猜你喜欢
  • 2015-02-03
  • 1970-01-01
  • 2016-11-13
  • 2011-10-25
  • 2012-12-15
  • 2015-06-02
  • 2021-03-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多