通过单击表格标题根据单元格背景色对表格进行排序

时间:2018-10-23 22:54:00

标签: javascript jquery html css

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

  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问题,但是在实现它们方面没有成功:

1 个答案:

答案 0 :(得分:1)

处理DOM中已存在的表

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

话虽如此,这是您如何从DOM中已经存在的表中提取信息并对其进行排序的方法。

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

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结构以按颜色排序;也就是说,您希望混洗已存在的tr个。一种更有效的方法是使表存在于抽象的数据结构中,以便从中提取表。任何需要进行的排序都将对数据结构完成,而DOM中的表将仅从该结构中更新。

一个包含背景颜色和单元格值的数据结构的简单示例可能以2D数组表示:

[ [ {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结构进行排序相比,该解决方案通常更健壮,效率更高,可维护性更好,并且可以将新条目以编程方式添加到表中。