描述

表格行必须在表格中的任意位置交换,即第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样式的框架,在我编写此框架时(随时间而变化),最重要的可能是ReactVue.jsAngular。我在下面提供了一个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处理)。

09-25 18:13
查看更多