如何使用js / html对表进行排序

时间:2018-11-21 09:02:39

标签: javascript html

我有一张桌子:

Name | Department | status 

我在单击时按字母顺序对名称进行排序,但是现在我在状态单元格中创建了一个下拉列表,其中显示诸如“内部/外部”之类的值,当我单击那些过滤器之一时,我想对表格进行排序,我只希望看到人们谁进/出。我当前的JS函数:

function sortStatusDesc() {
   var table, rows, switching, i, x, y, shouldSwitch;
   table = document.getElementById("myTable");
   switching = true;

   while (switching) {
      switching = false;
      rows = table.rows;

      for (i = 1; i < (rows.length - 1); i++) {
         shouldSwitch = false;
         x = rows[i].getElementsByTagName("th")[2];
         y = rows[i + 1].getElementsByTagName("th")[2];

         if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) {
            shouldSwitch = true;
            break;
         }
      }
      if (shouldSwitch) {
         rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
         switching = true;
      }
   }
}

按字母顺序排序。

3 个答案:

答案 0 :(得分:1)

下面的代码片段显示了对任何属性的排序。 单击属性标题之一可以更改排序。

以相同的方式,您可以创建过滤。不用data.sort()对特定属性的source_data进行排序,而是对所有具有正确值的条目进行data.filter()

//	Name of the data we're rendering.
const source_name = 'Locations';
//	Source data we want to create a table from.
const source_data = [
  { "id": 1, "name": "production hall", 	"department": "production", 	"status": "inside"	},
  { "id": 2, "name": "spare parts room",	"department": "production", 	"status": "inside"	},
  { "id": 3, "name": "warehouse",		"department": "production", 	"status": "inside"	},
  { "id": 4, "name": "loading bay",		"department": "production", 	"status": "outside"	},
  { "id": 5, "name": "offices HR",		"department": "administration",	"status": "inside"	},
  { "id": 6, "name": "offices QA",		"department": "administration",	"status": "inside"	},
  { "id": 7, "name": "security lounge",	        "department": "administration",	"status": "outside"	}
];
//  Create the table.
//  For this example, we'll use string manipulation to create the HTML.
//  For complex layouts a templating system is better.	
const render = ( name, data ) => {
  //	Always include a header for the name.
  //	When there's 0 rows, we'll still know what the table shows.
  const labels = data.length
    ? '<tr>' + Object.keys( data[ 0 ]).map( name => `<th data-attr="${ name }">${ name }</th>` ).join( '' ) + '</tr>'
    : '';
  //	Actual header for the properties of our data.
  const header = `<tr><th colspan="${ data.length || 1 }">${ name }</th></tr>${ labels }`;
  //	One row for each entry in our data.
  const rows = data.map( entry => (`<tr id="entry_${ entry.id }">` + Object.values( entry ).map( value => `<td>${ value }</td>` ).join( '' ) + '</tr>' )).join( '' );
  //	Merge it all together.
  const table = `<table><thead>${ header }</thead><tbody>${ rows }</tbody></table>`;
  //	Render into the page.
  document.querySelector( '#output' ).innerHTML = table;
};
//	Sort of the property.
const sort = ( data, property ) => {
  //  Sort the data on the property in alphabetical order.
  return data.sort(( first, second ) => {
    if ( first[ property ] < second[ property ] ) return -1;
    else if ( first[ property ] > second[ property ] ) return 1;
    else return 0;
  });
};
//	Add click events to the header so that clicking a header will sort the rows.
const add_sorting = function( table ) {
  Array
    .from( table.querySelectorAll( 'th' ))
    .forEach( header => header.addEventListener( 'click', create_table ));
};
//	Main function
const create_table = event => {
  // We'll reuse this function both manually and through clicking
  const property = event && event.target
    ? event.target.getAttribute( 'data-attr' )
    : event;
  const collection = sort( source_data, property );
  render( source_name, collection );
  add_sorting( document.querySelector( 'table' ));
};
create_table( 'name' );
th, td {
  border: 1px solid grey;
}
<div id="output"></div>

答案 1 :(得分:0)

可以使用<{>比较器函数轻松地对表节进行排序(例如“例如,该单元格应该出现在该单元格之前吗?” Math.min)。 3}}算法,此处展示了comparison sort,少于10行的实际表排序代码:

class InsertionSort {
    static sort_children(parent, comparator) {
        for(let i = 0; i != parent.children.length; i++) {
            const current = parent.children[i];
            let element;
            for(element = current.previousElementSibling; element && comparator(current, element); element = element.previousElementSibling);
            parent.insertBefore(current, element ? element.nextElementSibling : parent.firstElementChild);
        }
    }
}

具有一个表部分(或一个表)(上面parent的{​​{1}}参数),并且有许多行作为子元素,您可以使用上面定义的sort_children方法对其进行排序,只要您自己正确定义行的比较方式即可:

sort_children

上面对表格行进行排序,以便第一列的单元格按字典顺序显示。

InsertionSort.sort_children(your_table, (row_A, row_B) => row_A.cells[0].textContent < row_B.cells[0].textContent); 的第二个参数是前面提到的比较器函数sort_children,对于传递给它的任何两行,它应该返回comparator(row_A, row_B),其中true应该在{之前出现{1}},否则row_A。由于提供了比较器功能,因此您可以决定如何对行进行排序。

您可以通过自动使用row_B运算符,根据值格式(文本,数字等)创建返回返回特定于特定表列的比较器的函数来进一步适配比较器函数(为false<以及其他类型定义):

Number

然后使用不太冗长且更易读的表达式来调用表排序:

String

上面对行进行排序,以使第二列数值较低的单元格出现在数值较高的单元格之前。

答案 2 :(得分:0)

使用现有的行对表进行“过滤”,可以很容易地通过类切换来完成,其中包括:

function filter_table(section, predicate) {
    for(const row of section.rows) row.classList.toggle("filtered", predicate(row));
}

上面发生的是,section函数认为是“已过滤”的整个表或表节(上面的predicate)的行都通过在这些表或表节的“已过滤”类上切换来进行标记

predicate函数是您自己设计的函数,可以选择接受一个表行,如果应该过滤该行,则返回true,否则返回false

例如,以雇员行为例,假设每行的第三个表格单元格包含一个select(下拉)控件,其中一个选项用于“输入”,一个选项用于“输出” “:

<tr><!-- ... --><td><select><option value="in">In</option><option value="out">Out</option></select></tr>

您可以编写将根据“进入”或“离开”状态(示例中为“进入”)过滤员工行的谓词,如下所示:

const predicate = row => row.cells[2].firstElementChild.value == "in";

如何设置过滤后的行的样式取决于您,当然,您可能希望简单地隐藏它们:

tr.filtered {
    display: none;
}

由于每个员工的身份随着下拉选择的更改而有效地更改,因此您将为每个此类更改调用filter_table,然后通过 all 再次行。因此,最好监听select控件在更改其值时将触发的“更改”事件:

table.addEventListener("change", event => {
    if(event.target instanceof HTMLSelectElement) {
        const row = event.target.parentElement.parentElement;
        row.classList.toggle("filtered", predicate(row));
    }
})

您只需要在整个表上附加一个侦听器-“更改”事件使气泡化。上面定义的predicate函数已重用,但仅适用于单个更改的行。

P.S。在任何人选择跳车这样说并建议使用hidden属性之前,我都认为这里不合适,因为没有更多问题的信息-过滤后的行不是无效/不适用的文档节点,它只能被临时过滤,例如,以帮助根据变量读取表。除非您实际上想要删除这样的行,否则它是不同的。我相信目前的问题要求“感知”过滤。