描述
表格行必须在表格中的任意位置交换,即第i行和第j行必须更改位置,其中i和j不一定相邻。请参阅下面的当前实现。表行应按列排序; sort_index
指定一列,该列通过按下表标题之一生成。
该实现的问题在于,表的单击是通过标题的每次单击来进行递增排序的,而应通过单击来对其进行排序。
var table_index = {
watched: 0,
title: 1,
director: 2,
year: 3
};
var sort_index = 0;
$(document).ready(function()
{
var table_headers = document.getElementById("header-item").children;
for (var k = 0; k < table_headers.length; k++)
{
$("#" + table_headers[k].id).bind("click", function(e)
{
sort_index = table_index[e.target.id];
var table = document.getElementById("film-list");
for (var i = 1; i < table.rows.length - 1; i++)
{
var a = table.rows[i].getElementsByTagName("td")[sort_index].innerHTML;
for (var j = i + 1; j < table.rows.length; j++)
{
var b = table.rows[j].getElementsByTagName("td")[sort_index].innerHTML;
var swap = 0;
switch (sort_index)
{
// Alphabetic sort
case 0:
case 1:
case 2:
if (b.toLowerCase() < a.toLowerCase())
swap = 1;
break;
// Numeric sort
case 3:
if (b - a < 0)
swap = 1;
break;
}
if (swap == 1)
{
$(".row-item").eq(i - 1).after(table.rows[j]);
$(".row-item").eq(j - 1).after(table.rows[i]);
}
}
}
});
}
});
编辑
似乎真正的问题与循环内的闭包有关。单击标题时,实际上仅在DOM中更新最后一个表行交换,因此需要多次单击才能正确地对表进行排序。
我将为此发布自己的解决方案,以阐明实际问题。
最佳答案
我同意Mr Polywhirl的观点,即在DOM本身中这样做可能并不理想(尽管完全有可能,请参见下文)。现代Web开发倾向于使用模型/视图/控制器风格的架构(各种类型),其中模型(您的实际数据)与模型(DOM)的视图和控制器(浏览器,DOM和您的代码一起运行),对模型执行操作(然后在视图中反映出来)。有许多流行的MVC样式的框架,在我编写此框架时(随时间而变化),最重要的可能是React,Vue.js和Angular。我在下面提供了一个React示例。
但是同样,您可以直接在DOM上执行此操作。我看到您正在使用jQuery,因此在下面使用了它-请参阅内联注释。
// Hook `click` on the table header, but only call our callback if
// that click passes through a `th`
$(".sortable thead").on("click", "th", function() {
// Which column is this?
var index = $(this).index();
// Get the tbody
var tbody = $(this).closest("table").find("tbody");
// Disconnect the rows and get them as an array
var rows = tbody.children().detach().get();
// Sort it
rows.sort(function(left, right) {
// Get the text of the relevant td from left and right
var $left = $(left).children().eq(index);
var $right = $(right).children().eq(index);
return $left.text().localeCompare($right.text());
});
// Put them back in the tbody
tbody.append(rows);
});
td, th {
padding: 4px;
}
th {
cursor: pointer;
}
table {
border-collapse: collapse;
}
table, td, th {
border: 1px solid #ddd;
}
To sort the rows alphabetically by a column's contents, click its header.
<table class="sortable">
<thead>
<th>English</th>
<th>Spanish</th>
<th>Italian</th>
</thead>
<tbody>
<tr>
<td>One</td>
<td>Uno</td>
<td>Uno</td>
</tr>
<tr>
<td>Two</td>
<td>Dos</td>
<td>Due</td>
</tr>
<tr>
<td>Three</td>
<td>Tres</td>
<td>Tre</td>
</tr>
<tr>
<td>Four</td>
<td>Cuatro</td>
<td>Quattro</td>
</tr>
</tbody>
</table>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
可能会更短一些,但我想保持清晰而不是过于简洁。
请注意,这将删除行,对行进行排序,然后放回去,而不是引起各种就地DOM修改。
这是React示例:
// A React "component" for the table
class MyTable extends React.Component {
// Initializes the component
constructor(props) {
super(props);
this.state = {
// Start out unsorted, copying the array (but reusing the entries, as `row`
// properties -- we do that so we can use their original index as a key)
sorted: props.data.map((row, index) => ({index, row})),
sortKey: null
};
}
// Sort the view
sort(by) {
// Update state...
this.setState(({sorted, sortKey}) => {
if (sortKey === by) {
// ...no update needed, already sorting this way
return;
}
// Copy the array, then sort it (never change state in place)
sorted = sorted.slice();
sorted.sort((left, right) => left.row[by].localeCompare(right.row[by]));
// Return the state updates
return {sorted, sortKey: by};
});
}
// Render the component per current state
render() {
const {sorted} = this.state;
const {headers} = this.props;
return (
<table className="sortable">
<thead>
{headers.map(({title, lang}) => <th key={lang} onClick={() => this.sort(lang)}>{title}</th>)}
</thead>
<tbody>
{sorted.map(({row, index}) =>
<tr key={index}>
{headers.map(({lang}) => <td key={lang}>{row[lang]}</td>)}
</tr>
)}
</tbody>
</table>
);
}
}
// Mount the component
ReactDOM.render(
<MyTable
headers={[
{title: "English", lang: "en"},
{title: "Spanish", lang: "es"},
{title: "Italian", lang: "it"}
]}
data={[
{en: "One", es: "Uno", it: "Uno"},
{en: "Two", es: "Dos", it: "Due"},
{en: "Three", es: "Tres", it: "Tre"},
{en: "Four", es: "Cuatro", it: "Quattro"}
]}
/>,
document.getElementById("root")
);
td, th {
padding: 4px;
}
th {
cursor: pointer;
}
table {
border-collapse: collapse;
}
table, td, th {
border: 1px solid #ddd;
}
To sort the rows alphabetically by a column's contents, click its header.
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
它使用各种ES2015 +功能,例如解构,箭头功能和速记属性;并且还使用JSX语法(这不是JavaScript功能;由代码段中的Babel处理)。