首页 > 解决方案 > 如何对包含 json 对象的可观察数组进行排序?

问题描述

您好,我是淘汰 javascript 的新手,我有一个包含 json 对象的 observablearray。所以我试图按给定的顺序对对象列表进行排序。

像 yhis 一样声明 observablearray:

 var self =this;
 self.array= ko.observableArray();

我用这段代码遍历名为“array”的observablearray:

self.array().forEach(function(v,i){
 alert(JSON.stringify(v))
}

它返回我:

{"uuid":"74af2d36-aa47-45c5-af5d-b32c8ed56202","label":"a"}
{"uuid":"412f6222-e4c3-40a0-8a30-b1e31f53d746","label":"b"}
{"uuid":"115c9fa4-c43b-4ad0-bad7-855da850905f","label":"c"}
{"uuid":"55671032-9fc5-4361-8722-3d14abaa7d81","label":"d"}

我真的很想在我的新 observableArray 中加入这样的东西:

{"uuid":"115c9fa4-c43b-4ad0-bad7-855da850905f","label":"c"}
{"uuid":"74af2d36-aa47-45c5-af5d-b32c8ed56202","label":"a"}
{"uuid":"55671032-9fc5-4361-8722-3d14abaa7d81","label":"d"}
{"uuid":"412f6222-e4c3-40a0-8a30-b1e31f53d746","label":"b"}

标签: knockout.js

解决方案


JS排序101

要对数组进行排序,请使用Array.prototype.sort. 您向它传递一个函数,该函数接受两个项目,aand b,并返回1,-10

如果它返回1if acome after b-1if acome before b,并且0如果没有区别。

const stringSort = (a, b) => a.localeCompare(b);
const numericSort = (a, b) => a > b ? 1 : a < b ? -1 : 0;

const products = [
  { name: "Bread",       cost: 3.10 },
  { name: "Almond Milk", cost: 1.30 },
  { name: "Chocolate",   cost: 2.90 }
];

console.log(
  "By name:", 
  products.sort((p1, p2) => stringSort(p1.name, p2.name))
);

console.log(
  "By cost:", 
  products.sort((p1, p2) => numericSort(p1.cost, p2.cost))
);

请注意,您不能将助手直接传递给products.sort方法!您需要另一个函数来定义我们想要排序的属性。

使用淘汰赛

淘汰赛最酷的地方在于,您可以创建数据的排序版本,该版本会在源更改时自动更新!这是一个交互式示例来展示您可以做什么。

在下面的示例中:

  • 我在计算内部排序,以便 UI 的表自动更新
    • 添加产品时
    • 当您删除产品时
    • 当您更改排序方法时
    • 当你改变排序方向时

const stringCompare = (a, b) => a.localeCompare(b);
const numericCompare = (a, b) => a > b ? 1 : a < b ? -1 : 0;

const products = ko.observableArray([
  { name: "Bread",       cost: 3.10 },
  { name: "Almond Milk", cost: 1.30 },
  { name: "Chocolate",   cost: 2.90 }
]);

const sorters = [
  { 
    label: "By cost",
    sort: (a, b) => numericCompare(a.cost, b.cost)
  },
  { 
    label: "Alphabetically",
    sort: (a, b) => stringCompare(a.name, b.name)
  }
];

const desc = ko.observable(true);

const sorter = ko.observable(sorters[0]);
const sortMethod = ko.pureComputed(() => desc() 
  ? (a, b) => -1 * sorter().sort(a, b) 
  : sorter().sort
)

const sortedProducts = ko.pureComputed(() =>
  products().sort(sortMethod())
);

const newProduct = {
  name: ko.observable(""),
  cost: ko.observable(0)
};

const removeProduct = p => {
  products.remove(p);
}

const addProduct = () => {
  products.push({ 
    name: newProduct.name(),
    cost: +newProduct.cost() 
  });
  
  newProduct.name("");
  newProduct.cost(0);
};


ko.applyBindings({ sorters, desc, sortedProducts, newProduct, addProduct, removeProduct })
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<div>
  Sort by: <select data-bind="options: sorters, value: sorter, optionsText: 'label'"></select> 
  Descending <input type="checkbox" data-bind="checked: desc">
</div>

<table>
  <thead>
    <tr>
      <th>no.</th>
      <th>Name</th>
      <th>Cost</th>
      <th></th>
    </tr>
  </thead>
  <tbody data-bind="foreach: sortedProducts">
    <tr>
     <td data-bind="text: $index() + 1"></td>
     <td data-bind="text: name"></td>
     <td data-bind="text: '$' + cost.toFixed(2)"></td>
     <td>
       <button data-bind="click: $root.removeProduct">remove</button>
     </td>
    </tr>
  </tbody>
  <tbody data-bind="with: newProduct">
    <tr>
      <td></td>
      <td>
         <input data-bind="value: name" placeholder="product name">
      </td>
      <td>
        <input type="number" min="0" step="0.1" data-bind="value: cost">
       </td>
       <td>
         <button data-bind="click: addProduct">add</button>
       </td>
     </tr>
  </tbody>

</table>


推荐阅读