在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
的标志isEditing
是isEditing
。 我个人喜欢把这种types的“元数据”看作是一个可观测量的子观测量,如:
var name = ko.observable("Bob"); name.isEditing = ko.observable(false);
你将能够绑定name
和name.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一个通用的范围,通过定义函数中的公共数据。