敲除 foreach 中的自定义绑定以获取迭代器

Knockout custom binding in foreach to get iterator

我正在尝试制作要在 foreach 绑定中使用的自定义绑定,并且需要访问当前 observableArray$data.

现在我注意到 bindingContext arg 包含 $data, $parent, $root 等,但是我似乎无法找到一种方法来访问正在迭代的数组,那么有什么办法吗?

为了清楚起见,这里有一个例子可以说明我的意思:

<div data-bind="foreach: People">
   <button data-bind="customBinding: someArg">DoSomethingWithArrayAndElement</button>
</div>

在这种情况下 customBinding 似乎产生:

我不确定这是否可行,但在没有进一步了解您的应用程序的情况下,这是我唯一可以建议的事情:创建一个公开完整数组的自定义 foreach 绑定。

ko.bindingHandlers.customForeach = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
      var newBindingContext = bindingContext.extend({iterator: valueAccessor()});

      return ko.bindingHandlers.foreach.init(element, valueAccessor, allBindingsAccessor, viewModel, newBindingContext);
    },
    update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
      var newBindingContext = bindingContext.extend({iterator: valueAccessor()});

      return ko.bindingHandlers.foreach.update(element, valueAccessor, allBindingsAccessor, viewModel, newBindingContext);
    }
  };

var ViewModel = function ViewModel() {
  this.items = ko.observableArray(['a', 'b', 'c', 'd']);
  };

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

<ul data-bind="customForeach: items">
  <li data-bind="text: $data"></li>
</ul>

这会向您的 bindingContext 添加一个新的 iterator 属性,从其中公开整个数组。

所以您的目标是让底层数组在 foreach 模板中可访问?如果您问我,您 不应该 以那种方式为您的代码建模。

话虽如此,您真正需要的只是数组的别名,并确保在使用 foreach 绑定时设置别名。当然,您可以通过多种方式实现这一目标。

可能最干净的方法是创建一个 alias 绑定处理程序。然后扩展现有的 foreach 绑定以添加别名或创建一个新的。

ko.bindingHandlers.alias = {
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var value = valueAccessor();
        var aliasValue = value.data;
            aliasName = value.aliasName || '$alias';
        if (ko.isObservable(aliasValue)) {
            var rawValue = aliasValue,
                rawAliasName = value.rawAliasName || '$rawAlias';
            bindingContext[rawAliasName] = rawValue;
            aliasValue = rawValue();
        }
        bindingContext[aliasName] = aliasValue;
    }
};
ko.bindingHandlers.foreachex = {
    preprocess: function (value, name, addBinding) {
        addBinding('alias', "{ data: "+value+", aliasName: '$source', rawAliasName: '$rawSource' }");
        addBinding('foreach', value);
    }
};

然后你就可以使用你认为的别名了。

<div data-bind="foreachex: People">
    <!-- $rawSource is the People observable array -->
    <button data-bind="customBinding: someFunction($rawSource, $data)">
        DoSomethingWithArrayAndElement
    </button>
</div>

fiddle