【问题标题】:Sorting Observable Array in Knockouts JS在 Knockouts JS 中对 Observable 数组进行排序
【发布时间】:2015-01-17 01:35:49
【问题描述】:

好的...所以我正在使用 Twitter Bootstrap。我有一个可观察的数组,它代表一组组。在 UI 中,这个 observableArray 用于为每个组呈现一个“选项卡”和“选项卡窗格”。我可以按名称属性对这些组进行排序和显示,没有问题,轻而易举!

<ul data-bind="foreach: myArray().sort(function (l, r) { return l.name() > r.name() ? 1 : -1 })" class="nav nav-tabs" role="tablist">
    <li data-bind="text: name"></li>
</ul>

太好了……但是,我在同一个数组中有一个“全部”对象,它需要位于正在显示的选项卡集的开头。

标签当前看起来像这样... A |全部 |乙| C | D

需要看起来像这样...全部 |一个 |乙| C | D

有什么想法吗? :-/

【问题讨论】:

  • A 位于 All 之前,因此您的排序是正确的。如果您希望它以不同的方式排序,那么您必须添加一个子句来处理All。但是把模型逻辑从你的视图中取出,放到computed属性中,这样会干净很多。
  • 感谢您的反馈。我知道“A”在“All”之前,哈哈。只是不确定如何在视图中添加额外的条件,但你已经回答了我的问题,我认为......我会尝试放入一个计算属性。

标签: javascript twitter-bootstrap knockout.js


【解决方案1】:

调整您的排序功能。在 OO 方式中,“All”对象将具有一个属性,指示它应该在顶部排序。或者,快速而肮脏的方法是将您的排序功能调整为如下所示:

function (l, r) {
    if (l.name === "All") return 1;
    if (r.name === "All") return -1;
    return l.name().localeCompare(r.name());
}

认为我的 +1/-1 逻辑是正确的,但你有单元测试来解决这些细节,对吧? ;)

作为旁注,我会使用localeCompare 函数来比较字符串。


继@MattBurland 的评论之后,您也应该将排序逻辑移动到您的视图模型中(无论如何,这都是对它进行单元测试所必需的)。另外注意sort会对数组本身进行排序,你也可以在observable上调用sort(不调用它作为函数来获取observable的值),对observable的内容进行排序。

这就是它的样子:

function ViewModel(items) {
  var self = this;
  self.myArray = (items);
  self.myArray.sort(function (l, r) {
      if (l.name() === "All") return -1;
      if (r.name() === "All") return 1;
      return l.name().localeCompare(r.name());
  });
};

var vm = new ViewModel([
  { name: ko.observable("B") },
  { name: ko.observable("A") },
  { name: ko.observable("All") }
]);

ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<ul data-bind="foreach: myArray" class="nav nav-tabs" role="tablist">
    <li data-bind="text: name"></li>
</ul>

或者像这样,如果你使用 OO 方法:

function ViewModel(items) {
  var self = this;
  self.myArray = (items);
  self.myArray.sort(function (l, r) {
      if (!!l.isSpecialOption) return -1;
      if (!!r.isSpecialOption) return 1;
      return l.name().localeCompare(r.name());
  });
};

var vm = new ViewModel([
  { name: ko.observable("B") },
  { name: ko.observable("A") },
  { name: ko.observable("All"), isSpecialOption: true }
]);

ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<ul data-bind="foreach: myArray" class="nav nav-tabs" role="tablist">
    <li data-bind="text: name"></li>
</ul>

【讨论】:

  • 感谢您的反馈,我会尽快回复您;-)
【解决方案2】:

我会在 ViewModel 中处理所有这些,而不是在模板中进行。理想的解决方案是您的 allTab 已经与其他选项卡分开,但如果不是,您可能需要遍历其他选项卡并找到它。

vm.sortedTabs = ko.computed(function () {
    var allTab = ?;
    var otherTabs = ?; //I don't know enough about your VM to know where you get these

    return [allTab].concat(otherTabs.sort(sortFunction)); 
});

那么你的模板就是

<ul data-bind="foreach: sortedTabs" class="nav nav-tabs" role="tablist">
    <li data-bind="text: name"></li>
</ul>

但是这种排序逻辑在 VM 中比在模板中的内联更容易处理。

与 Jeroen 的回答相比,我认为处理特殊选项卡然后对其余选项卡进行排序要清晰得多,而不是尝试将处理特殊选项卡的逻辑放入排序算法中。

【讨论】:

    猜你喜欢
    • 2023-03-21
    • 2019-09-06
    • 2022-11-22
    • 2015-10-19
    • 1970-01-01
    • 1970-01-01
    • 2020-06-29
    • 2020-04-16
    • 1970-01-01
    相关资源
    最近更新 更多