在init和update之间为自定义挖空绑定存储状态的首选方法是什么?

目前我正在使用jQuery数据为dom元素存储状态。

ko.bindingHandlers.customValue = { init: function init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { var state = { isEditing: false }; $(element).focus(function focus() { state.isEditing = true; }).blur(function blur() { state.isEditing = false; }).data("customBinding", state); }, update: function update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { // ignore if updating if (!$(element).data("customBinding").isEditing) { // handle update if they are not updating } } };​ 

有一个更好的地方存储每个绑定不需要dom的状态? bindingContext是否可以用来存储绑定的每个实例的状态?

bindingContext是一种可能性,但仅用于从init传递数据以在第一次update绑定时触发。 下一次update激发将不再存在。

存储这种types的状态的确有两种select:

1-就元素而言,如你所述。 您可以使用jQuery的$.data或KO包含API来执行此操作以及ko.utils.domData.get(element, key)ko.utils.domData.set(element, key, value)

2-将这种types的信息放在视图模型中(如果适用)。 在视图模型中,指示isEditing的标志isEditingisEditing 。 我个人喜欢把这种types的“元数据”看作是一个可观测量的子观测量,如:

 var name = ko.observable("Bob"); name.isEditing = ko.observable(false); 

你将能够绑定namename.isEditing

这有一些优点:

  • 保持视图模型相当干净,因为您没有引入新的顶级属性
  • 保持与其父可观察性相关的子可观察性(不需要nameIsEditing等)
  • 当转换成类似于ko.toJSON的JSON时, isEditing子可观察isEditing将在其父解包时简单地被删除。 所以,你不会将不必要的值发送回服务器。
  • 在这种情况下,它也可以具有在视图模型中可用于其他计算的优点,或者绑定到UI中的多个元素。

将数据附加到元素是很好的,Knockout在内部使用这个方法来控制stream绑定(例如,with等)。

另一种方法是只使用init函数,并使用计算的observable来处理更新。 我在重复绑定中使用这个方法。 这里是重要的部分:

 ko.bindingHandlers['repeat'] = { 'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { ... // set up persistent data var lastRepeatCount = 0; ... ko.computed(function() { var repeatCount = ko.utils.unwrapObservable(valueAccessor()); ... // Remove nodes from end if array is shorter for (; lastRepeatCount > repeatCount; lastRepeatCount--) { ... } ... // Add nodes to end if array is longer (also initially populates nodes) for (; lastRepeatCount < repeatCount; lastRepeatCount++) { ... } }, null, {'disposeWhenNodeIsRemoved': placeholder}); ... } }; 

我经常使用这种模式:

 define(['knockout'], function(ko) { var interInstanceVariable = null; function Tree(element) { var privateInstanceVariable = null; function privateInstanceMethod() {} this.publicInstanceMethod = function() {} } ko.bindingHandlers.cannDendrogram = { init: function(element, valueAccessor) { $(element).data('tree', new Tree(element)); }, update: function(element, valueAccessor) { var tree = $(element).data('tree'); tree.publicMethod(); } }; }); 

我意识到这个问题是古老的,但是我偶然发现了这个方法,所以我想用更现代的方法来解决问题。

您可以直接将属性添加到bindingContext。$ data。 我select了一个令人讨厌的variables名“___IsEditing”,以避免潜在的冲突,但是你明白了…

 ko.bindingHandlers.customValue = { init: function init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { bindingContext.$data.___IsEditing = false; $(element).focus(function focus() { bindingContext.$data.___IsEditing = true; }).blur(function blur() { bindingContext.$data.___IsEditing = false; }).data("customBinding", state); }, update: function update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { // ignore if updating if (bindingContext.$data.___IsEditing) { // handle update if they are not updating } } 

};

我使用一个函数来为init和update创build一个通用的范围,通过定义函数中的公共数据。