随机化Knockout.js中的Foreach列表项

时间:2017-03-17 20:14:54

标签: random knockout.js data-binding foreach

尝试使用foreach有序列表并将列表项随机播放。我创建了一个函数( randomOrder )并在foreach项的绑定中使用它。 似乎没什么用。

HTML:

<ol data-bind="foreach: { data: docs, randomOrder: true} ">
     <li class="result" data-bind="component: { name: 'physicianreferral.docresult', params: { doc: $data } }"></li>
</ol>

JS:

    ko.bindingHandlers.randomOrder = {
        init: function (elem, valueAccessor) {
            // Build an array of child elements
            var child = ko.virtualElements.firstChild(elem),
                childElems = [];
            while (child) {
                childElems.push(child);
                child = ko.virtualElements.nextSibling(child);
            }

            // Remove them all, then put them back in a random order
            ko.virtualElements.emptyNode(elem);
            while (childElems.length) {
                var randomIndex = Math.floor(Math.random() * childElems.length),
                    chosenChild = childElems.splice(randomIndex, 1);
                ko.virtualElements.prepend(elem, chosenChild[0]);
            }
        }
    };
    ko.virtualElements.allowedBindings.randomOrder = true;

2 个答案:

答案 0 :(得分:2)

首先,您的绑定不属于foreach,因此必须在顶级指定:

foreach: docs, randomOrder: true

但我建议你根本不使用这种方法。只需将传递给foreach的数组随机化:

foreach: randomize(docs)

JS:

function randomize(arr) {
    var newArray = [];
    while (arr.length) {
        var randomIndex = Math.floor(Math.random() * arr.length);
        newArray.push(arr.splice(randomIndex, 1)[0]);
    }
    return newArray;
};

答案 1 :(得分:0)

一些问题:首先,您尝试在foreach绑定中使用自定义绑定。您可以在同一HTML元素中使用多个绑定,但它们应以逗号分隔。

<ol data-bind="foreach: { data: docs }, randomOrder: true">

自定义绑定'init'方法具有allBindingAccessor,它提供了一种访问视图模型属性的方法,这些属性在同一元素的其他绑定中使用。

var array = allBindingsAccessor().foreach.data();

使用可用的数组,您可以使用任何算法来重新排列它。我在片段中添加了Fisher-Yates(aka Knuth)Shuffle,直接从这个answer复制。点击“运行代码段”,每次都看到它被洗牌。

ko.bindingHandlers.randomOrder = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var array = allBindingsAccessor().foreach.data();

        var currentIndex = array.length, temporaryValue, randomIndex;

        // while there remain elements to shuffle...
        while (0 !== currentIndex) {

            // Pick a remaining element...
            randomIndex = Math.floor(Math.random() * currentIndex);
            currentIndex -= 1;

            // And swap it with the current element.
            temporaryValue = array[currentIndex];
            array[currentIndex] = array[randomIndex];
            array[randomIndex] = temporaryValue;
        }

        allBindingsAccessor().foreach.data(array);
    }
};

var ViewModel = function() {
    var self = this; 

    self.docs = ko.observableArray([1, 2, 3, 4, 5, 6, 7, 8 ,9, 10]);
};

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

<ol data-bind="foreach: { data: docs }, randomOrder: true">
    <li data-bind="text: $data"></li>
</ol>