【问题标题】:knockout.js sorted observable arrayknockout.js 排序的可观察数组
【发布时间】:2013-03-09 01:51:28
【问题描述】:

我想要一个可观察的数组,当一个对象被推入其中时它会自行排序(如果它在比较器函数中使用的任何值发生更改,它会自行排序会更好)。

您可以定义您希望数组排序的比较器函数,然后每次调用 push 时,它会将推送的对象添加到数组中的正确位置,以便数组保持排序,例如:

var sortedArray = ko.sortedObservableArray(
    function (a,b) { return b - a;},
    [1,7,4]
); // sortedArray will be [1,4,7]
sortedArray.push([5,2]); // sortedArray will now be [1,2,4,5,7]

是否有任何库可以为我执行此操作,如果没有,实现此操作的最佳方法是什么?

【问题讨论】:

    标签: javascript knockout.js


    【解决方案1】:

    我最终通过扩展敲除可观察数组创建了一个排序的可观察数组:

    ko.sortedObservableArray = function (sortComparator, initialValues) {
        if (arguments.length < 2) {
            initialValues = [];
        }
        var result = ko.observableArray(initialValues);
        ko.utils.extend(result, ko.sortedObservableArray.fn);
        delete result.unshift;
        result.sort(sortComparator);
        return result;
    };
    
    ko.sortedObservableArray.fn = {
        push: function (values) {
            if (!$.isArray(values)) {
                values = [values];
            }
            var underlyingArray = this.peek();
            this.valueWillMutate();
            underlyingArray.push.apply(underlyingArray, values);
            underlyingArray.sort(this.sortComparator);
            this.valueHasMutated();
        },
        sort: function (sortComparator) {
            var underlyingArray = this.peek();
            this.valueWillMutate();
            this.sortComparator = sortComparator;
            underlyingArray.sort(this.sortComparator);
            this.valueHasMutated();
        },
        reinitialise: function (values) {
            if (!$.isArray(values)) {
                values = [values];
            }
            var underlyingArray = this.peek();
            this.valueWillMutate();
            underlyingArray.splice(0, underlyingArray.length);
            underlyingArray.push.apply(underlyingArray, values);
            underlyingArray.sort(this.sortComparator);
            this.valueHasMutated();
        },
        reverse: function () {
            var underlyingArrayClone = this.peek().slice();
            underlyingArrayClone.reverse();
            return underlyingArrayClone;
        }
    };
    

    可以通过以下方式使用:

    var sortedArray = ko.sortedObservableArray(
        function (a,b) { return a - b;},
        [1,7,4]
    ); // sortedArray will be [1,4,7]
    sortedArray.push([5,2]); // sortedArray will now be [1,2,4,5,7]
    sortedArray.sort(function (a,b){
        return b - a;
    }); // sortedArray will now be [7,5,4,2,1]
    sortedArray.push(6); // sortedArray will now be [7,6,5,4,2,1]
    

    我遇到的唯一问题是,当使用新数组重新初始化已排序的可观察数组时,与重新初始化可观察数组的方式相同,已排序的可观察数组没有被排序。为了解决这个问题,我在排序后的可观察数组上添加了一个重新初始化函数:

    var sortedArray = ko.sortedObservableArray(
        function (a,b) { return a - b;},
        [1,7,4]
    ); // sortedArray will be [1,4,7]
    
    sortedArray([3,2,8]); // this doesn't work correctly, sortedArray will be [3,2,8]
    // instead of [2,3,8]
    
    // To get around this you can use reinitialise()
    sortedArray.reinitialise([3,2,8]); // sortedArray will be [2,3,8]
    

    【讨论】:

      【解决方案2】:

      试试这个:

      var sortedArray = ko.observableArray();
      sortedArray.subscribe(function () {
          if (!sortedArray._isSorting) {
              sortedArray._isSorting = true;
              sortedArray.sort(function (a, b) { return b - a; });
              sortedArray._isSorting = false;
          }
      });
      

      您可以将其包装在一个函数中,以便随时创建新的排序的可观察数组。

      【讨论】:

      • 你不需要额外的标志。 JavaScript 是一种只有一个执行行的语言,没有线程。因此,这意味着在sort 操作期间没有任何东西可以改变observableArray 的值
      • @Serjio - 即使是单线程代码也需要关注可重入性。调用sortedArray.sort 将触发对sortedArray.notifySubscribers() 的另一个调用,这将最终再次递归调用我们的订阅回调。
      • 是的,我明白了。谢谢
      猜你喜欢
      • 2019-12-16
      • 2018-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-03
      • 2013-07-28
      • 1970-01-01
      • 2012-06-30
      相关资源
      最近更新 更多