Javascript 在Knockout中增加数组项上下文

Javascript 在Knockout中增加数组项上下文,javascript,knockout.js,foreach,Javascript,Knockout.js,Foreach,目前,当使用Knockoutforeach绑定时,您可以使用$index访问当前索引。我想为我的内部绑定提供其他类似的功能,例如: 阵列(允许我访问正在操作的阵列) 长度(所述阵列的长度) first(当前项是否为第一项) last(当前项是否为最后一项) 仅(当前项目是否为唯一项目) 你明白了。不幸的是,设置$index的代码被深埋在模板绑定的代码中,没有明显的方式来扩展上下文 我可以通过自定义的foreach绑定来访问array和length,该绑定扩展了bindingContext(我

目前,当使用Knockout
foreach
绑定时,您可以使用
$index
访问当前索引。我想为我的内部绑定提供其他类似的功能,例如:

  • 阵列
    (允许我访问正在操作的阵列)
  • 长度
    (所述阵列的长度)
  • first
    (当前项是否为第一项)
  • last
    (当前项是否为最后一项)
  • (当前项目是否为唯一项目)
你明白了。不幸的是,设置
$index
的代码被深埋在
模板
绑定的代码中,没有明显的方式来扩展上下文

我可以通过自定义的
foreach
绑定来访问
array
length
,该绑定扩展了
bindingContext
(我知道这个re:
destroy
有一些注意事项,但它对我有效),但我不知道如何实现需要访问“当前”的其他方法没有为每个数组迭代执行的自定义内部绑定的项

我希望能够做到这样:

<div data-bind="foreach: items">
  <input type="text" data-bind="value: description" />
  <button data-bind="visible: $last, click: $array.push({})">Add Another</button>      
</div>

再加一个
(我们知道,
$array
$last
都不存在)。假设
按钮
元素可能来自外部模板,无法知道如何指向当前数组(因此
$parent.items.push对我不起作用)

有没有办法做到这一点?

您可以使用$parent.data()获取实际数组

对于
$length
,您可以执行以下操作:

$parent.items.length
$index() == 0
$index() == ($parent.items.length - 1)
$index() == 0 && $parent.items.length == 1
对于
$first
,您可以执行以下操作:

$parent.items.length
$index() == 0
$index() == ($parent.items.length - 1)
$index() == 0 && $parent.items.length == 1
对于
$last
,您可以执行以下操作:

$parent.items.length
$index() == 0
$index() == ($parent.items.length - 1)
$index() == 0 && $parent.items.length == 1
对于
,您可以执行以下操作:

$parent.items.length
$index() == 0
$index() == ($parent.items.length - 1)
$index() == 0 && $parent.items.length == 1
以下是。

您可以使用$parent.data()获取实际数组

对于
$length
,您可以执行以下操作:

$parent.items.length
$index() == 0
$index() == ($parent.items.length - 1)
$index() == 0 && $parent.items.length == 1
对于
$first
,您可以执行以下操作:

$parent.items.length
$index() == 0
$index() == ($parent.items.length - 1)
$index() == 0 && $parent.items.length == 1
对于
$last
,您可以执行以下操作:

$parent.items.length
$index() == 0
$index() == ($parent.items.length - 1)
$index() == 0 && $parent.items.length == 1
对于
,您可以执行以下操作:

$parent.items.length
$index() == 0
$index() == ($parent.items.length - 1)
$index() == 0 && $parent.items.length == 1

下面是一个例子。

我能想到的最好办法是创建专门的绑定,用于存储有关数组和当前项的上下文信息

自定义
foreach
绑定,用于公开数组的上下文:

ko.bindingHandlers.xforeach = (function() {
    var createContext = function(array) {
        return {
            '$array': array,
            '$arrayLength': function() { return ko.unwrap(array).length; }
        };
    };
    return {
        init: ko.bindingHandlers.foreach.init,
        update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
            var extendedContext = createContext(valueAccessor());
            return ko.bindingHandlers.foreach.update.call(this, element, valueAccessor, allBindings, viewModel, bindingContext.extend({
                '$foreachContext' : extendedContext
            }));
        }    
    };
})();
ko.virtualElements.allowedBindings.xforeach = true;
自定义
模板
绑定,用于公开有关项/数组的上下文:

ko.bindingHandlers.xforeachItem = (function() {
    var createContext = function(currentContext, forEachContext) {
        return {
            first: function() { return currentContext.$index() === 0; },
            last: function() { return currentContext.$index() === (forEachContext.$arrayLength() - 1); }
        };
    };
    return {
        init: ko.bindingHandlers.template.init,
        update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
            var extendedContext = createContext(bindingContext, bindingContext.$parentContext.$foreachContext);
            return ko.bindingHandlers.template.update.call(this, element, valueAccessor, allBindings, viewModel, bindingContext.extend({
                '$foreachItemContext' : extendedContext
            }));
        }
    };
})();
ko.virtualElements.allowedBindings.xforeachItem = true;
用法示例:

<div data-bind="xforeach: items">
    <div data-bind="xforeachItem: {}">
        <input type="text" data-bind="value: description" />        
        <span data-bind="visible: $foreachItemContext.first(), text: $foreachContext.$arrayLength()"></span>
        <button data-bind="visible: $foreachItemContext.last(), click: $root.add">Add Another</button>
    </div>
</div>

再加一个

最后,一个提琴显示了它的作用:

我能想到的最好办法是创建专门的绑定来存储关于数组和当前项的上下文信息

自定义
foreach
绑定,用于公开数组的上下文:

ko.bindingHandlers.xforeach = (function() {
    var createContext = function(array) {
        return {
            '$array': array,
            '$arrayLength': function() { return ko.unwrap(array).length; }
        };
    };
    return {
        init: ko.bindingHandlers.foreach.init,
        update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
            var extendedContext = createContext(valueAccessor());
            return ko.bindingHandlers.foreach.update.call(this, element, valueAccessor, allBindings, viewModel, bindingContext.extend({
                '$foreachContext' : extendedContext
            }));
        }    
    };
})();
ko.virtualElements.allowedBindings.xforeach = true;
自定义
模板
绑定,用于公开有关项/数组的上下文:

ko.bindingHandlers.xforeachItem = (function() {
    var createContext = function(currentContext, forEachContext) {
        return {
            first: function() { return currentContext.$index() === 0; },
            last: function() { return currentContext.$index() === (forEachContext.$arrayLength() - 1); }
        };
    };
    return {
        init: ko.bindingHandlers.template.init,
        update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
            var extendedContext = createContext(bindingContext, bindingContext.$parentContext.$foreachContext);
            return ko.bindingHandlers.template.update.call(this, element, valueAccessor, allBindings, viewModel, bindingContext.extend({
                '$foreachItemContext' : extendedContext
            }));
        }
    };
})();
ko.virtualElements.allowedBindings.xforeachItem = true;
用法示例:

<div data-bind="xforeach: items">
    <div data-bind="xforeachItem: {}">
        <input type="text" data-bind="value: description" />        
        <span data-bind="visible: $foreachItemContext.first(), text: $foreachContext.$arrayLength()"></span>
        <button data-bind="visible: $foreachItemContext.last(), click: $root.add">Add Another</button>
    </div>
</div>

再加一个

最后,一把小提琴在演奏中表现出来:

也许我误解了你,但这行不通
$parent
将引用父对象(在最简单的情况下是页面的viewModel),然后您必须知道数组的名称才能访问它。例如:
$parent.items().length
在上面的示例中。看见此外,我希望能够使用更简洁的
first
last
only
函数来帮助处理冗长的内容。我仍然不知道它会如何工作。我从未听说过或见过任何关于KO的隐含信息,称为
data
(除了
$data
,但它指的是
foreach
中的当前项)。继续,将该小提琴中的
$parent.items().length
更改为
$parent.data().length
——它不起作用(
数据
不存在)。你能用那把小提琴来展示你在说什么吗?我加了一把小提琴并编辑了我的答案。我一般使用
数据
作为数组的名称。我知道我可以通过名称引用数组,我想要的是一种不需要知道就可以访问正在迭代的数组的一般方法。也许我误解了你,但这不起作用
$parent
将引用父对象(在最简单的情况下是页面的viewModel),然后您必须知道数组的名称才能访问它。例如:
$parent.items().length
在上面的示例中。看见此外,我希望能够使用更简洁的
first
last
only
函数来帮助处理冗长的内容。我仍然不知道它会如何工作。我从未听说过或见过任何关于KO的隐含信息,称为
data
(除了
$data
,但它指的是
foreach
中的当前项)。继续,将该小提琴中的
$parent.items().length
更改为
$parent.data().length
——它不起作用(
数据
不存在)。你能用那把小提琴来展示你在说什么吗?我加了一把小提琴并编辑了我的答案。我一般使用
data
作为数组的名称。我知道我可以通过名称引用数组,我想要的是一种访问正在迭代的数组的一般方法,而不必知道这一点。