【问题标题】:knockout js - Table sorting using column headers淘汰赛 js - 使用列标题对表格进行排序
【发布时间】:2019-11-14 20:10:32
【问题描述】:

我是淘汰 js 的新手,需要帮助了解如何使用列标题对表格进行动态排序。

以下是我的代码的一部分:

HTML:

<table>
    <thead>
        <tr data-bind="click: sortFunction">
            <th id='id'>Id</th>
            <th id='name'>Name</th>
            <th id='description'>Description</th>
        </tr>
    </thead>
    <tbody data-bind="foreach: deptList">
        <tr>
            <td><span data-bind="text: id" /></td>
            <td><span data-bind="text: name" /></td>
            <td><span data-bind="text: description" /></td>
        </tr>    
    </tbody>
</table>

在我的视图模型中,我有以下函数,用于使用表头对数据表进行排序。

视图模型:

self.deptList = ko.observableArray(mylist);
self.sortColumn = ko.observable("id");
self.isSortAsc = ko.observable("True");

var Dept = function(id, name, description) {
    this.id = ko.observable(id);
    this.name = ko.observable(name);
    this.description = ko.observable(description);
};

var mylist = [
    new Dept(1, "Dept 1", "D1"),
    new Dept(2, "Dept 2", "D6"),
    new Dept(3, "Dept 3", "D3"),
    new Dept(4, "Dept 4", "D4")
];

self.sortFunction = function(data, event) {

    if (self.sortColum === event.target.id)
        self.isSortAsc = !self.isSortAsc;
    else {
        self.sortColumn = event.target.id;
        self.isSortAsc = "True";
    }

    self.deptList.sort(function(a, b) {
        if (self.sortColum === 'id') {
            if (self.isSortAsc)
                a.id < b.id ? -1 : 1;
            else
                a.name < b.name ? 1 : -1;
        } else if (self.sortColum === 'name') {
            if (self.isSortAsc)
                a.name < b.name ? -1 : 1;
            else
                a.name < b.name ? 1 : -1;
        } else(self.sortColum === 'description') {
            if (self.isSortAsc)
                a.description < b.description ? -1 : 1;
            else
                a.description < b.description ? 1 : -1;
        }

    });
};

尽管上面的代码可以正常工作,但我认为应该有更好的方法来做到这一点(我的意思是将列 id 作为参数传递),这在有大量列时会很有用。

我尝试了left[self.sortColumn] &lt; right[self.sortColumn] ? -1 : 1,但没有按预期工作。

如果可以通过动态列名进行排序,请显示示例代码。

提前致谢。

【问题讨论】:

    标签: knockout.js html-table


    【解决方案1】:

    这是一个快速的 bindingHandler,您可以将其添加到您的 th 中。单击 th 后,它将根据绑定中定义的属性名称对列进行排序。

    ko.bindingHandlers.sort = {
        init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
            var asc = false;
            element.style.cursor = 'pointer';
    
            element.onclick = function(){
                var value = valueAccessor();
                var prop = value.prop;
                var data = value.arr;
    
                asc = !asc;
    
                data.sort(function(left, right){
                    var rec1 = left;
                    var rec2 = right;
    
                    if(!asc) {
                        rec1 = right;
                        rec2 = left;
                    }
    
                    var props = prop.split('.');
                    for(var i in props){
                        var propName = props[i];
                        var parenIndex = propName.indexOf('()');
                        if(parenIndex > 0){
                            propName = propName.substring(0, parenIndex);
                            rec1 = rec1[propName]();
                            rec2 = rec2[propName]();
                        } else {
                            rec1 = rec1[propName];
                            rec2 = rec2[propName];
                        }
                    }
    
                    return rec1 == rec2 ? 0 : rec1 < rec2 ? -1 : 1;
                });
            };
        }
        };
    

    这更优雅一点,因为您不必为每列创建单独的函数。可以在此处找到更完整的工作示例:http://jsfiddle.net/brendonparker/6S85t/

    【讨论】:

    • 因为我的属性是可观察的,所以我需要用 ko.unwrap 包装对 left[prop] 和 right[prop] 的调用。
    • 查看更新的 sn-p 和 fiddle。我对其进行了一些改进,以处理对本身是可观察的属性的排序。
    • 对于那些希望使用 brendonparker 代码的人,如果您的属性是可淘汰的 observable,您必须像这样指定您的绑定:data-bind="sort: {arr: array, prop: field( )}”。注意字段名称后的 ()。否则会按照访问函数的内存地址排序。
    【解决方案2】:
    left[self.sortColumn] < right[self.sortColumn] ? -1 : 1
    

    不起作用,因为 self.sortColumn 是一个 ko.observable,您必须通过将其作为函数调用来获取其值。

    self.deptList.sort(function (a, b) {
      if(self.isSortAsc())
         a[self.sortColumn()]() < b[self.sortColumn()]() ? -1 : 1;
      else
         a[self.sortColumn()]() < b[self.sortColumn()]() ? 1 : -1;
    });
    

    而且您还需要在诸如

    之类的可观察对象上设置值
    if(self.sortColum === event.target.id)
                        self.isSortAsc(!self.isSortAsc());
                    else
                    {
                        self.sortColumn(event.target.id);
                        self.isSortAsc("True");
                    }
    

    而不是

    if(self.sortColum === event.target.id)
                        self.isSortAsc = !self.isSortAsc;
                    else
                    {
                        self.sortColumn = event.target.id;
                        self.isSortAsc = "True";
                    } 
    

    我已经整理了一个工作示例

    <table class="dept_table">
      <thead>
          <tr data-bind="click: sortFunction">
              <th id='id'>Id</th>
              <th id='name'>Name</th>
              <th id='description'>Description</th>
          </tr>
      </thead>
    
      <tbody data-bind="foreach: deptList">
          <tr>
                  <td><span data-bind="text: id" /></td>
                  <td><span data-bind="text: name" /></td>
                  <td><span data-bind="text: description" /></td>
          </tr>    
      </tbody>
    </table>
    <script>
    // deptlist data
    var mylist = [
                {id:1, name:"Dept 1", description: "D1"},
                {id:2, name:"Dept 2", description: "D6"},
                {id:3, name:"Dept 3", description: "D3"},
                {id:4, name:"Dept 4", description: "D4"}];
    
    // Deptlist-item Viewmodel
    var Dept = function (data) {
      var self = this;
    
      for(var key in data){
        // this is the lazy approach usually you should only use observables where they are needed
        if(data.hasOwnProperty(key))this[key] = ko.observable(data[key]);
      }
    };
    
    // Deptlist Viewmodel
    var Deptlist = function(table_data){
      var self = this;
    
      this.deptList = ko.observableArray([]);
      this.sortColumn = ko.observable("id");
      this.isSortAsc = ko.observable(true);
    
      for(var i = 0;i < table_data.length;i++){
        if(table_data.hasOwnProperty(i))this.deptList.push(new Dept(table_data[i]));
      }
    
      this.sortFunction = function(){
        if(self.sortColumn() === event.target.id)
            self.isSortAsc(!self.isSortAsc());
        else
        {
            self.sortColumn(event.target.id);
            self.isSortAsc(true);
        }
    
        self.deptList.sort(function (a, b) {
                if(a[self.sortColumn()]() < b[self.sortColumn()]())return !self.isSortAsc();
                else return self.isSortAsc();
        });
      }
    };
    
    var deptList = new Deptlist(mylist);
    
    ko.applyBindings(deptList,$('.dept_table')[0]);
    
    </script>
    

    【讨论】:

    • 并使用真正的布尔值而不是“true”和“false”,因为非空字符串评估为 true
    • 非常感谢您的指示和示例代码。当我将 (data, event) 指定为函数参数时,上述示例确实有效。 (this.sortFunction = 函数(数据,事件){)。但是,如果我最初单击 Id 列本身,它应该按降序对 id 进行排序。但奇怪的是给出了 3、1、2、4 的值。我需要 4、3、2、1(用于 Id 的降序)。你能仔细检查一下吗?再次感谢。
    • 确保在比较函数中访问的值类似于 a[self.sortColumn()]()
    • self.deptList.sort(function (a, b) { if(self.isSortAsc()) return a[self.sortColumn()]()
    • self.deptList.sort(function (a, b) { if(self.isSortAsc()) return !(a[self.sortColumn()]()
    【解决方案3】:

    感谢 @brendonparker 提供的出色 bindingHandler。

    我进一步扩展了它以处理哪个表头处于活动状态,然后在元素上应用sorting 类以及asc。这样,如果表头正在排序并且设置为 asc 或 desc,您可以使用 CSS 向最终用户显示。

    ko.bindingHandlers.sort = {
        init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
    
    
            var asc = ko.observable(false);
    
            var value = valueAccessor();
            var prop = value.prop;
            var data = value.arr;
    
            if(!bindingContext.$data['currentClicked'])
            {
                bindingContext.$data['currentClicked'] = ko.observable();
            }
    
    
            var isActive = ko.computed(function()
            {
                return (bindingContext.$data['currentClicked']() === prop)
            });
    
    
            ko.applyBindingsToNode(element, {
                        css: {'sorting': isActive, 'asc': asc}
                    }, bindingContext);
    
    
            element.onclick = function(){
    
                asc(!asc())
    
                bindingContext.$data['currentClicked'](prop);                       
    
                data.sort(function(left, right){
                    var rec1 = left;
                    var rec2 = right;
    
                    if(!asc()) {
                        rec1 = right;
                        rec2 = left;
                    }
    
                    var props = prop.split('.');
    
                    for(var i in props)
                    {
                        var propName = props[i];
                        var parenIndex = propName.indexOf('()');
    
                        if(ko.isWriteableObservable(rec1[propName]))
                        {
                            rec1 = rec1[propName]();
                            rec2 = rec2[propName]();
                        } else {
                            rec1 = rec1[propName];
                            rec2 = rec2[propName];
                        }
                    }
    
                    return rec1 == rec2 ? 0 : rec1 < rec2 ? -1 : 1;
                });
            };
        }
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-04
      • 1970-01-01
      • 2013-11-27
      • 1970-01-01
      • 1970-01-01
      • 2014-07-09
      • 2018-01-09
      相关资源
      最近更新 更多