目前我正在使用dom元素的jQuery数据存储状态。
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可以用于存储绑定的每个实例的状态吗?
答案 0 :(得分:47)
bindingContext
是可能的,但仅限于在第一次触发绑定时将数据从init
传递到update
。 update
下一次发射它将不再存在。
存储此类状态的位置实际上有两种选择:
1-在元素上,如你所说。您可以使用jQuery的$.data
或KO包含API来执行此操作ko.utils.domData.get(element, key)
和ko.utils.domData.set(element, key, value)
。
2-如果合适,将此类信息放入视图模型中。指示isEditing
的标志在视图模型中不一定不合适。我个人喜欢把这种类型的“元数据”作为子观察者从像以下观察者那样:
var name = ko.observable("Bob");
name.isEditing = ko.observable(false);
您可以绑定name
和name.isEditing
。
这有一些优点:
nameIsEditing
等)。ko.toJSON
之类的内容转换为JSON时,{parent} {sub} obseable将在其父项被解包时被删除。因此,您不会将不必要的值发送回服务器。答案 1 :(得分:8)
将数据附加到元素很好,Knockout在内部使用此方法进行控制流绑定(例如,if,with等)。
另一种方法是仅使用init
函数并使用计算的observable来处理更新。我在repeat绑定中使用此方法。以下是重要部分:
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});
...
}
};
答案 2 :(得分:1)
我经常使用这种模式:
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();
}
};
});
答案 3 :(得分:1)
我意识到这个问题已经过时了,但我在这里偶然发现了这种方法,因此我认为我会采用更现代的方法。
您可以直接向bindingContext。$ data添加属性。我选择了一个恼人的变量名称“___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
}
}
};
答案 4 :(得分:-2)
我使用函数通过定义函数内部的公共数据来为init和update创建一个公共范围。