【问题标题】:Backbone.js collection comparator sort by multiple fields?Backbone.js 集合比较器按多个字段排序?
【发布时间】:2012-01-19 05:56:08
【问题描述】:
  this.col = Backbone.Collection.extend({
    model: M,
    comparator: function(item) {
      return item.get("level");
    }
  });

上面的代码按级别对项目进行排序。我想按级别排序,然后按标题。我可以这样做吗?谢谢。

【问题讨论】:

标签: javascript sorting backbone.js


【解决方案1】:

@amchang87 的答案肯定有效,但我发现另一个有效的方法只是返回一个可排序字段的数组:

this.col = Backbone.Collection.extend({
    model: M,
    comparator: function(item) {
      return [item.get("level"), item.get("title")]
    }
});

我还没有在多个浏览器中对此进行测试,因为我认为它依赖于 JS 在数组排序顺序中的行为(基于它们的内容)。它绝对适用于 WebKit。

【讨论】:

  • 从 2012 年初开始支持排序样式的比较器。只需接受 2 个参数并返回 -1、0 或 1。github.com/documentcloud/backbone/commit/…
  • 如此直截了当,这种技术就是。这是 CoffeeScript 中的一个示例:gist.github.com/jhabdas/9822535
  • 请注意(至少在 Webkit 中)这两个字段将作为字符串进行比较。如果您尝试进行数字排序,您最终会得到 1、10、2、20、200 等。
  • @RobW:不完全是,它实际上最终会比较字符串化数组而不是它们的元素,所以这个答案是不正确的,只会偶然起作用。
  • @RobW 你是对的。如果我有 2 个数字字段而不是文本字段,我该如何实现?
【解决方案2】:

在按升序对多个字段进行排序时,字符串连接工作正常,但它对我不起作用,因为 1)我必须支持每个字段的 asc/desc 和 2)某些字段是数字字段(即,我想要 10 到如果它正在上升,则在 2 之后)。因此,下面是我使用的比较器功能,并且可以满足我的需要。它假设主干集合有一个分配有“sortConfig”的变量,这是一个带有字段名称和排序方向的 JSON 对象数组。例如,

{
    "sort" : [
        {
            "field": "strField",
            "order": "asc"
         },
         {
             "field": "numField",
             "order": "desc"
         },
         ...
     ]
}

将上面的JSON对象赋值为'sortConfig'给集合,下面的函数会让Backbone先按strField升序排序,然后按numField降序排序,依此类推。如果没有指定排序顺序,则排序默认升序。

multiFieldComparator: function(one, another) {
    // 'this' here is Backbone Collection
    if (this.sortConfig) {
        for (var i = 0; i < this.sortConfig.length; i++) {
            if (one.get(this.sortConfig[i].field) > another.get(this.sortConfig[i].field)) {
                return ("desc" != this.sortConfig[i].order) ? 1 : -1;
            } else if (one.get(this.sortConfig[i].field) == another.get(this.sortConfig[i].field)) {
                // do nothing but let the loop move further for next layer comparison
            } else {
                return ("desc" != this.sortConfig[i].order) ? -1 : 1;
            }
        }
    }
    // if we exited out of loop without prematurely returning, the 2 items being
    // compared are identical in terms of sortConfig, so return 0
    // Or, if it didn't get into the if block due to no 'sortConfig', return 0
    // and let the original order not change.
    return 0;
}

【讨论】:

    【解决方案3】:

    如果您需要降序排序和一些升序排序,则返回数组不一致...

    我创建了一组函数,可用于将相关的比较整数返回给 Backbone Comparator 函数:

    backbone-collection-multisort

    【讨论】:

      【解决方案4】:

      主要的是 Backbone 按一个项目与另一个项目的单个相对值进行排序。所以不可能直接在一个集合中排序两次,但我会试试这个。

      this.col = Backbone.Collection.extend({
          model: M,
          comparator: function(item) {
            // make sure this returns a string!
            return item.get("level") + item.get("title");
          }
      });
      

      这将返回一个类似“1Cool”、“1title”、“2newTitle”的字符串...... Javascript 应该先按数字字符对字符串进行排序,然后再按每个字符排序。但这仅在您的级别具有相同数量的数字时才有效。 IE“001title”与“200title”。主要思想是您需要生成两个可比较的对象,一行是数字或字符串,它们可以根据一个标准相互比较。

      其他解决方案是使用下划线“groupby”您的关卡,然后使用“sortby”手动对每个关卡组进行排序,然后用这个新创建的数组手动替换底层集合。每当集合“更改”时,您可能可以设置一个函数来执行此操作。

      【讨论】:

      • 如果我理解'groupby' 方法会弄乱我的数据建模,不是吗?第一个解决方案有点好,所以谢谢。
      • 不确定这是最好的方法。例如,如果你有 2 个模型:model1-> level: 1, title: "1-thing"; model2 -> level: 10, title: "-thing",那么你会期望它被排序 model1, model2 - 但是通过那个比较器,它会比较字符串 "11-thing" 和 "10-thing",所以会以错误的顺序排序
      • 这与尝试按数组排序的功能相同,从单个参数比较器函数返回 [1,'x'] 将按字符串 "1,x" 排序,而不是比较元素。
      【解决方案5】:

      hyong 回答中的“灵感”。

      这也允许你在比较之前更改数据,valueTransforms 是一个对象,如果该对象中有一个具有功能的属性,它将被使用。

          /*
           * @param {Object} sortOrders ie: 
           * {
           *     "description": "asc",
           *     "duedate": "desc",
           * }
           * @param {Object} valueTransforms
           */
          setMultiFieldComparator: function(sortOrders, valueTransforms) {
              var newSortOrders = {}, added = 0;
              _.each(sortOrders, function(sortOrder, sortField) {
                  if (["asc", "desc"].indexOf(sortOrder) !== -1) {
                      newSortOrders[sortField] = sortOrder;
                      added += 1;
                  }
              });
              if (added) {
                  this.comparator = this._multiFieldComparator
                      .bind(this, newSortOrders, valueTransforms || this.model.prototype.valueTransforms || {});
              } else {
                  this.comparator = null;
              }
          },
      
          _multiFieldComparator: function(sortOrders, valueTransforms, one, another) {
              var retVal = 0;
              if (sortOrders) {
                  _.every(sortOrders, function(sortOrder, sortField) {
                      var oneValue = one.get(sortField),
                          anotherValue = another.get(sortField);
                      if (valueTransforms[sortField] instanceof Function) {
                          oneValue = valueTransforms[sortField](oneValue);
                          anotherValue = valueTransforms[sortField](anotherValue);
                      }
                      if (oneValue > anotherValue) {
                          retVal = ("desc" !== sortOrder) ? 1 : -1;
                      } else if (oneValue < anotherValue) {
                          retVal = ("desc" !== sortOrder) ? -1 : 1;
                      } else {
                          //continue
                          return true;
                      }
                  });
              }
              return retVal;
          },
      

      【讨论】:

        猜你喜欢
        • 2014-03-28
        • 2021-05-02
        • 1970-01-01
        • 1970-01-01
        • 2020-07-19
        • 1970-01-01
        • 2013-09-10
        相关资源
        最近更新 更多