【问题标题】:jQuery: Sort table by multiple column valuesjQuery:按多列值对表进行排序
【发布时间】:2018-10-02 00:55:57
【问题描述】:

我已经为此苦苦挣扎了一段时间,每次我测试某些东西时,我最终都会得到不同的结果。

JSFIDDLE

我有一个用于测试目的的基本表,其中包含 3 个条目,这些条目有 3 个不同的标题,按以下顺序排序:姓名、年龄、加入日期。

这是表格:

<table class="table">
<thead>
  <tr>
    <th scope="col">#</th>
    <th scope="col" id="firstName">name</th>
    <th scope="col" id="age">age</th>
    <th scope="col" id="date">date joined</th>
  </tr>
</thead>
<tbody>
  <tr>
    <th scope="row">1</th>
    <td class="firstName">Mark</td>
    <td>12</td>
    <td>12/02/2006</td>
  </tr>
  <tr>
    <th scope="row">2</th>
    <td class="firstName">Jacob</td>
    <td>30</td>
    <td>03/04/2018</td>
  </tr>
  <tr>
    <th scope="row">3</th>
    <td class="firstName">Larry</td>
    <td>22</td>
    <td>07/01/2009</td>
  </tr>
</tbody>

这是我的 JS:

function sortTable(column) {
        var $tbody = $('.table tbody');
        $tbody.find('td.' + column).sort(function(a,b){ 
            var tda = $(a).find('td:eq(1)').text();
            var tdb = $(b).find('td:eq(1)').text();
                    // if a < b return 1
            return tda < tdb ? 1 
                   // else if a > b return -1
                   : tda > tdb ? -1 
                   // else they are equal - return 0    
                   : 0;           
        }).appendTo($tbody);
}

$('#firstName').click(function() {
    sortTable("firstName");
});
$('#age').click(function() {
    sortTable("age");
});
$('#date').click(function() {
    sortTable("date");
});

我想要达到的目标

我希望能够单击每个标题以按其各自的内容对表格进行排序。因此,例如,当我单击名称时,它将按名称排序。当我单击年龄时,它将按年龄排序,当我单击加入日期时,它将按日期排序。

我也很想学习,所以我会给一个有很好的 cmets 的答案,可以为我解释发生了什么。

谢谢。

function sortTable(column) {
  var $tbody = $('.table tbody');
  $tbody.find('td.' + column).sort(function(a, b) {
    var tda = $(a).find('td:eq(1)').text();
    var tdb = $(b).find('td:eq(1)').text();
    // if a < b return 1
    return tda < tdb ? 1
      // else if a > b return -1
      :
      tda > tdb ? -1
      // else they are equal - return 0    
      :
      0;
  }).appendTo($tbody);
}

$('#firstName').click(function() {
  sortTable("firstName");
});
$('#age').click(function() {
  sortTable("age");
});
$('#date').click(function() {
  sortTable("date");
});
@import 'https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css';
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="table">
  <thead>
    <tr>
      <th scope="col">#</th>
      <th scope="col" id="firstName">name</th>
      <th scope="col" id="age">age</th>
      <th scope="col" id="date">date joined</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">1</th>
      <td class="firstName">Mark</td>
      <td>12</td>
      <td>12/02/2006</td>
    </tr>
    <tr>
      <th scope="row">2</th>
      <td class="firstName">Jacob</td>
      <td>30</td>
      <td>03/04/2018</td>
    </tr>
    <tr>
      <th scope="row">3</th>
      <td class="firstName">Larry</td>
      <td>22</td>
      <td>07/01/2009</td>
    </tr>
  </tbody>
</table>

【问题讨论】:

    标签: jquery sorting html-table


    【解决方案1】:

    目前,您正在对&lt;td&gt; 进行排序,这实际上是一个单元格而不是行(&lt;tr&gt;)。

    .sort的回调函数有2个参数。您需要比较这 2 个参数并且:

    1. 如果第一个参数应该在前,则返回负值。
    2. 如果第二个参数应该在前,则返回一个正值。
    3. 如果位置没有变化,则返回 0。

    您必须根据数据的类型(数字、文本、日期)来比较数据。也使用列的索引而不是文本,因为我认为它更容易。

    function sortTable(column, type) {
    
      //Get and set order
      //Use -data to store wheater it will be sorted ascending or descending
      var order = $('.table thead tr>th:eq(' + column + ')').data('order');
      order = order === 'ASC' ? 'DESC' : 'ASC';
      $('.table thead tr>th:eq(' + column + ')').data('order', order);
    
      //Sort the table
      $('.table tbody tr').sort(function(a, b) {
      //                                 ^  ^
      //                                 |  | 
      //        The 2 parameters needed to be compared. 
      //        Since you are sorting rows, a and b are <tr>                                 
    
        //Find the <td> using the column number and get the text value.
        //Now, the a and b are the text of the <td>
        a = $(a).find('td:eq(' + column + ')').text();
        b = $(b).find('td:eq(' + column + ')').text();
    
        switch (type) {
          case 'text':
            //Proper way to compare text in js is using localeCompare
            //If order is ascending you can - a.localeCompare(b)
            //If order is descending you can - b.localeCompare(a);
            return order === 'ASC' ? a.localeCompare(b) : b.localeCompare(a);
            break;
          case 'number':
            //You can use deduct to compare if number.
            //If order is ascending you can -> a - b. 
            //Which means if a is bigger. It will return a positive number. b will be positioned first
            //If b is bigger, it will return a negative number. a will be positioned first
            return order === 'ASC' ? a - b : b - a;
            break;
          case 'date':
            var dateFormat = function(dt) {
              [m, d, y] = dt.split('/');
              return [y, m - 1, d];
            }
    
            //convert the date string to an object using `new Date`
            a = new Date(...dateFormat(a));
            b = new Date(...dateFormat(b));
    
            //You can use getTime() to convert the date object into numbers. 
            //getTime() method returns the number of milliseconds between midnight of January 1, 1970
            //So since a and b are numbers now, you can use the same process if the type is number. Just deduct the values.
            return order === 'ASC' ? a.getTime() - b.getTime() : b.getTime() - a.getTime();
            break;
        }
    
      }).appendTo('.table tbody');
    }
    
    $('#firstName').click(function() {
      sortTable(1, 'text');
    });
    $('#age').click(function() {
      sortTable(2, 'number');
    });
    $('#date').click(function() {
      sortTable(3, 'date');
    });
    table {
      font-family: arial, sans-serif;
      border-collapse: collapse;
      width: 100%;
    }
    
    td,
    th {
      border: 1px solid #dddddd;
      text-align: left;
      padding: 8px;
    }
    
    tr:nth-child(even) {
      background-color: #dddddd;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <table class="table">
      <thead>
        <tr>
          <th scope="col">#</th>
          <th scope="col" id="firstName">name</th>
          <th scope="col" id="age">age</th>
          <th scope="col" id="date">date joined</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td scope="row">1</td>
          <td class="firstName">Mark</td>
          <td>12</td>
          <td>12/02/2006</td>
        </tr>
        <tr>
          <td scope="row">2</td>
          <td class="firstName">Jacob</td>
          <td>30</td>
          <td>03/04/2018</td>
        </tr>
        <tr>
          <td scope="row">3</td>
          <td class="firstName">Larry</td>
          <td>22</td>
          <td>07/01/2009</td>
        </tr>
      </tbody>

    【讨论】:

    • 你能解释一下代码的作用吗?也许再放一些 cmets。例如,我不知道你为什么在里面有“column + 1”?
    • @JamesG 我添加了一些 cmets。关于column + 1,我更新了代码以减少混乱。
    • 如果您有任何问题,请告诉我。
    【解决方案2】:

    您可以在 tr 而不是 td 上进行排序。

    演示

    $('#firstName').click(function() {
      sortTable("firstName", this);
    });
    $('#age').click(function() {
      sortTable("age", this);
    });
    $('#date').click(function() {
      sortTable("date", this);
    });
    
    function sortTable(column, me) {
      var table = $(me).parents('table').eq(0),
        rows = table.find('tr:gt(0)').toArray().sort(doComparer($(this).index()))
      me.asc = !me.asc
      if (!me.asc) {
        rows = rows.reverse()
      }
    
      for (var i = 0; i < rows.length; i++) {
        table.append(rows[i])
      }
    }
    
    function doComparer(index) {
      return function(a, b) {
        a = getCellValue(a, index);
        b = getCellValue(b, index);
        return $.isNumeric(a) && $.isNumeric(b) ? a - b : a.toString().localeCompare(b)
      }
    }
    
    function getCellValue(row, index) {
      return $(row).children('td').eq(index).text()
    }
    th {
      cursor: pointer;
    }
    <link href="//stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" rel="stylesheet" />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <table class="table">
      <thead>
        <tr>
          <th scope="col">#</th>
          <th scope="col" id="firstName">name</th>
          <th scope="col" id="age">age</th>
          <th scope="col" id="date">date joined</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <th scope="row">1</th>
          <td class="firstName">Mark</td>
          <td>12</td>
          <td>12/02/2006</td>
        </tr>
        <tr>
          <th scope="row">2</th>
          <td class="firstName">Jacob</td>
          <td>30</td>
          <td>03/04/2018</td>
        </tr>
        <tr>
          <th scope="row">3</th>
          <td class="firstName">Larry</td>
          <td>22</td>
          <td>07/01/2009</td>
        </tr>
      </tbody>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-04
      • 1970-01-01
      • 1970-01-01
      • 2018-08-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多