【问题标题】:Knockout.js: How to sort table?Knockout.js:如何对表格进行排序?
【发布时间】:2019-04-16 22:43:54
【问题描述】:

我用这个例子:

http://stevescodingblog.co.uk/real-time-system-resource-monitor-with-signalr-mvc-knockout-and-webapi/#comment-3293

表格显示可观察数组。该数组由客户端通过信号器更新。一切正常。 我想按选定的列添加排序。

<div id="computerInfo">

<h2>Real-time System Resource Monitor</h2>
<h5 data-bind="visible: connected">Connected to message hub</h5>

<table border="0" class="table table-striped">
    <tr>
        <th>Machine</th>
        <th>CPU %</th>
        <th>Memory Available (Mb)</th>
        <th>Total Memory (Mb)</th>
        <th>Mem Available %</th>
    </tr>

    <!-- ko foreach: machines -->
    <tr data-bind="css: { highCpu: cpu() > 90 || memPercent()<30 }">
        <td data-bind="text: machineName"></td>
        <td data-bind="text: cpu"></td>
        <td data-bind="text: memUsage"></td>
        <td data-bind="text: memTotal"></td>
        <td data-bind="text: memPercent"></td>
    </tr>
    <!-- /ko -->

</table>

$(function () {

    // The view model that is bound to our view
    var ViewModel = function () {
        var self = this;

        // Whether we're connected or not
        self.connected = ko.observable(false);

        // Collection of machines that are connected
        self.machines = ko.observableArray();

        self.headers = [
                            { title: 'Machine Name', sortKey: 'keyMachineName' },
                            { title: 'CPU', sortKey: 'keyCpu' },
                            { title: 'Mem Usage', sortKey: 'keyMemUsage' },
                            { title: 'Mem Total', sortKey: 'keyMemTotal' },
                            { title: 'Mem Percent', sortKey: 'keyMemPercent' }
        ];
        self.sort = function (header, event) {
            var sortKey = header.sortKey;
            //implementation of sort
        };
        self.sort = function (header, event) {
            var sortKey = header.sortKey;
            switch (sortKey) {
                case 'keyMachineName':
                    self.machines.sort(function (a, b) {
                        var n = a.machineName < b.machineName ? -1 : a.machineName > b.machineName ? 1 : 0;
                        alert(n);
                        return n;//1;
                    });
                    break;
                case 'keyCpu':
                    self.machines.sort(function (a, b) {
                        var n = a.cpu < b.cpu ? -1 : a.cpu > b.cpu ? 1 : 0;
                        alert(n);
                        return n;
                    });
                    break;
                case 'keyMemUsage':
                    self.machines.sort(function (a, b) {
                        var n = a.memUsage < b.memUsage ? -1 : a.memUsage > b.memUsage ? 1 : 0;
                        alert(n);
                        return n;
                    });
                    break;
            }
        };
    };

    // Instantiate the viewmodel..
    var vm = new ViewModel();

    // .. and bind it to the view
    //ko.applyBindings(vm, $("#computerInfo")[0]);

    // Get a reference to our hub
    var hub = $.connection.cpuInfo;

    // Add a handler to receive updates from the server
    hub.client.cpuInfoMessage = function (machineName, cpu, memUsage, memTotal) {

        var machine = {
            machineName: machineName,
            cpu: cpu.toFixed(0),
            memUsage: (memUsage / 1024).toFixed(2),
            memTotal: (memTotal / 1024).toFixed(2),
            memPercent: ((memUsage / memTotal) * 100).toFixed(1) + "%"
        };

        var machineModel = ko.mapping.fromJS(machine);

        // Check if we already have it:
        var match = ko.utils.arrayFirst(vm.machines(), function (item) {
            return item.machineName() == machineName;
        });

        if (!match) {
            vm.machines.push(machineModel);
        } else {
            var index = vm.machines.indexOf(match);
            vm.machines.replace(vm.machines()[index], machineModel);
        }

       // vm.machines.sort();


        //ko.applyBindings(vm, $("#computerInfo")[0]);

        //$("#infoTable").tablesorter({sortList: [0,0]});
    };

    ///


    ko.applyBindings(vm, $("#computerInfo")[0]);
    ///
    // Start the connectio
    $.connection.hub.start().done(function () {
        vm.connected(true);
    });
});

问题是: sort 函数总是返回 0,即值总是相同的:

var n = a.machineName

当我为测试返回 1 时,排序工作正常。

【问题讨论】:

    标签: javascript asp.net knockout.js


    【解决方案1】:

    当你使用创建机器时

    var machineModel = ko.mapping.fromJS(machine);
    

    您创建了一个具有可观察属性的视图模型。在这种情况下,在您的排序方法中,您需要将它们视为可观察的,因此您必须使用括号来使用它们。例如:

    case 'keyMachineName':
        self.machines.sort(function (a, b) {
            var n = a.machineName() < b.machineName() ? -1 : a.machineName() > b.machineName() ? 1 : 0;
            alert(n);
            return n;//1;
        });
    break;
    

    【讨论】:

      【解决方案2】:

      jQuery 表格排序器插件不适用于淘汰赛。算了吧。

      当 DOM 节点在其不知情的情况下移动时,Knockout 无法处理,但这就是 jQuery Tablesorter 所做的。

      但是,knockout 已经准备好为您整理桌子了。

      以下示例功能

      • 完全可配置的列,即视图中没有硬编码
      • 点击时可排序的表格列,包括作为排序列的视觉反馈
      • 交替升序/降序排序
      • 通过Knockout extender 格式化值
      • 在一个区间内自动更新值(本用例中的可能场景)
      • 值更新时自动重新排序

      ko.extenders.formatted = function (underlyingObservable, formatFunction) {
          underlyingObservable.formatted = ko.computed(function () {
              return formatFunction(underlyingObservable());
          });
      };
      
      function Machine(data) {
          var self = this,
              memoryFormat = function (val) { return Math.round(val / 1024, 0).toLocaleString(); };
              
          self.machineName = ko.observable().extend({formatted: function (val) { return val; }});
          self.cpu = ko.observable(0).extend({formatted: function (val) { return val.toFixed(1); }});
          self.memUsage = ko.observable(0).extend({formatted: memoryFormat});
          self.memTotal = ko.observable(0).extend({formatted: memoryFormat});
          self.memPercent = ko.computed(function () {
              return self.memUsage() / self.memTotal() * 100;
          }).extend({formatted: function (val) { return val.toFixed(1) + '%'; }});
          self.conditions = ko.computed(function () {
              return {
                  highCpu: self.cpu() > 50,
                  lowMem: self.memPercent() < 30
              };
          });
          
          self.update(data);
      };
      Machine.prototype.update = function (data) {
          ko.mapping.fromJS(data, {}, this);
      };
      
      function MachineList() {
          var self = this;
      
          self.connected = ko.observable(false);
          self.machines = ko.observableArray();
          self.headers = [
              {title: 'Machine Name', key: 'machineName', cssClass: ''},
              {title: 'CPU %', key: 'cpu', cssClass: 'right'},
              {title: 'Mem Usage (MB)', key: 'memUsage', cssClass: 'right'},
              {title: 'Mem Total (MB)', key: 'memTotal', cssClass: 'right'},
              {title: 'Mem Available %', key: 'memPercent', cssClass: 'right'}
          ];
          self.sortHeader = ko.observable(self.headers[0]);
          self.sortDirection = ko.observable(1);
          self.toggleSort = function (header) {
              if (header === self.sortHeader()) {
                  self.sortDirection(self.sortDirection() * -1);
              } else {
                  self.sortHeader(header);
                  self.sortDirection(1);
              }
          };
      
          // use a computed to subscribe to both self.sortHeader() and self.sortDirection()
          self.sortMachines = ko.computed(function () {
              var sortHeader = self.sortHeader(),
                  dir = self.sortDirection(),
                  tempMachines = self.machines(),
                  prop = sortHeader ? sortHeader.key : "";
              if (!prop) return;
              tempMachines.sort(function (a, b) {
                  var va = ko.unwrap(a[prop]),
                      vb = ko.unwrap(b[prop]);                
                  return va < vb ? -dir : va > vb ? dir : 0;
              });
              self.machines.notifySubscribers();
          });
          self.insertMachine = function (data) {
              var machine = ko.utils.arrayFirst(vm.machines(), function (item) {
                  return ko.unwrap(item.machineName) == ko.unwrap(data.machineName);
              });
      
              if (machine) machine.update(data);
              else vm.machines.push(new Machine(data));
              self.sortMachines();
          };
      };
      
      // -------------------------------------------------------------------------------
      
      // connection mockup
      $.connection = {
          cpuInfo: {client: {}},
          hub: {start: function() { return $.Deferred().resolve(); }}
      };
      
      var vm = new MachineList(),
          hub = $.connection.cpuInfo;
      
      hub.client.cpuInfoMessage = function (data) { vm.insertMachine(data); };
      
      // start the connection as soon as possible...
      $.connection.hub.start().done(function () {
          vm.connected(true);
          $(function () {
              // ...but don't apply bindings before the document is ready
              ko.applyBindings(vm, $("#computerInfo")[0]);
          });
      
          // create some random sample data
          setInterval(function () {
              var GB = 1024 * 1024;
              ['A', 'B', 'C', 'D'].forEach(function (name) {
                  hub.client.cpuInfoMessage({
                      machineName: name,
                      cpu: getRandomInt(0, 1000) / 10,
                      memUsage: getRandomInt(5 * GB, 7 * GB),
                      memTotal: 10 * GB
                  });
              });
          }, 1000);
      });
      
      // -------------------------------------------------------------------------------
      
      function getRandomInt(min, max) {
          min = Math.ceil(min);
          max = Math.floor(max);
          return Math.floor(Math.random() * (max - min + 1)) + min;
      }
      .table { border-collapse: collapse; }
      .table th, .table td { border: 1px solid silver; padding: 0 2px; }
      .sortable { cursor: pointer; }
      .table-striped tbody tr:nth-child(odd) { background-color: #f7f7f7; }
      .highCpu { color: red; }
      .lowMem { color: red; }
      .right { text-align: right; }
      .sorted { background-color: #B5E0FF; }
      <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>
      
      <div id="computerInfo">
        <h2>Real-time System Resource Monitor</h2>
        <h5 data-bind="visible: connected">Connected to message hub</h5>
      
        <table border="0" class="table table-striped">
          <thead>
            <tr data-bind="foreach: headers">
              <th class="sortable" data-bind="click: $root.toggleSort, text: title, css: {sorted: $data === $root.sortHeader()}"></th>
            </tr>
          </thead>
          <tbody data-bind="foreach: machines">
            <tr data-bind="foreach: $root.headers, css: conditions">
              <td data-bind="text: $parent[key].formatted, css: cssClass"></td>
            </tr>
          </tbody>
        </table>
      </div>

      【讨论】:

        猜你喜欢
        • 2021-08-27
        • 1970-01-01
        • 1970-01-01
        • 2019-03-04
        • 2014-08-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-05
        相关资源
        最近更新 更多