【问题标题】:Knockout custom binding in foreach to get iterator在 foreach 中敲除自定义绑定以获取迭代器
【发布时间】:2018-03-20 00:10:15
【问题描述】:

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

现在我注意到 bindingContext arg 包含 $data, $parent, $root 等,但是我似乎找不到访问正在迭代的数组的方法,有没有办法?

为了清楚起见,这里是我的意思的一个例子:

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

在这种情况下customBinding 似乎屈服了:

  • $data = 迭代中的当前元素
  • $parent = 包含People 数组的视图模型
  • root = 与 $parent 相同
  • $index = 迭代数组中的当前索引
  • $parents = 包含视图模型的数组

【问题讨论】:

  • 你可能不得不从不同的角度来攻击它。你的自定义绑定应该做什么,它需要数组?
  • 我在各种视图模型中有很多重复的代码,这些代码使用其他一些常见的逻辑进行了一些添加/删除,所以我试图通过移动常见的东西来改进这种重用到自定义绑定(因为每个实例中的逻辑都是相同的)。所以这只是我试图减少代码来维护。
  • 如果您要访问当前正在迭代的数组,您只需在 custombindings 中使用 viewModel.people() 即可。 viewModel 提供您所需要的。欢呼
  • Viewmodel 在自定义绑定中已被弃用,而且它实际上不再可重用,因为您必须为每种类型进行绑定,或者确保它们都具有相同的变量名。跨度>
  • 那是周到的。你确定viewModel 被贬值了,我仍然在文档中找到它吗?谢谢

标签: javascript knockout.js


【解决方案1】:

我不确定这是否可行,但如果不进一步了解您的应用,我唯一可以建议的是:创建一个自定义 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 属性,从而从其中公开整个数组。

【讨论】:

  • 感谢这个例子,我会考虑是否真的值得我添加这种方法来节省几行重复,尽管目前它重复了大约 20 次。在大多数情况下,关键逻辑只是从活动数组中删除当前元素并触发事件(通过事件系统)。因此,如果我们只是将其视为从数组中删除条目而无需任何视图模型函数的快捷方式,这就是这些快捷方式绑定的关键所在。
  • 这就是我的意思——感觉就像一个杂牌,可能还有更好的方法。也许提出一个新问题,重点是“我怎样才能删除重复的代码”?
  • 我强烈区分“视图模型”(包含可通过 UI 执行的功能的对象)和数据模型。在我的应用程序中,foreach 中的“删除此数组条目”通常只是 click: $parent.removeItem.bind($parent, $data)$parent 是具有 function removeItem(item) { this.items.remove(item); } 的视图模型。
  • 好吧,所有的道路都会导致将逻辑放入视图模型中,无论是通过某种继承或丰富实例,还是像当前那样直接放入其中,或者将其放入自定义绑定中.我认为它不是真正的业务逻辑,只是一个简单的可重复操作,它作为自定义绑定更可重用且更易于管理,因为它不需要遍历所有源代码,就像你会做的那样使用 AOP 风格的技术将横切关注点从业务逻辑代码中移出。
  • 我明白你的意思。我在使用 Knockout 时遇到的几个问题之一是,我发现绑定在命名空间、组合等方面更难正确管理。另一方面,对于视图和数据模型,这些年来我已经开发出相当不错的结构。这就是为什么我倾向于在可能的情况下使用它们而不是绑定。
【解决方案2】:

所以您的目标是让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

【讨论】:

  • 事实证明,已经有一个开放的请求,要求将一些类似的功能添加到淘汰赛中:github.com/knockout/knockout/issues/662 以允许提到的用例。但是,您已经可以在 foreach 范围内访问 $index,所以我不明白为什么访问迭代器是一件坏事,它只允许上下文快捷方式绑定。
猜你喜欢
  • 2012-06-09
  • 2013-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-11
相关资源
最近更新 更多