57

目前我正在使用 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 可以用于存储绑定的每个实例的状态吗?

4

5 回答 5

48

bindingContext是一种可能性,但仅用于将数据从initupdate一次触发绑定传递。下次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);

您将能够绑定nameand name.isEditing

这有一些优点:

  • 保持视图模型相当干净,因为您没有引入新的顶级属性
  • 保持子可观察对象与其父可观察对象相关联(不需要nameIsEditing等)
  • 当转换为带有子可观察对象之类ko.toJSON的JSON时,它的父对象被解包时将被简单地丢弃。isEditing因此,您不会将不必要的值发送回服务器。
  • 在这种情况下,它还具有可用于视图模型中的其他计算或绑定 UI 中的多个元素的优点。
于 2012-04-17T01:17:18.687 回答
9

将数据附加到元素上很好,例如,Knockout 在内部使用此方法进行控制流绑定(if、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});
        ...
    }
};
于 2012-05-15T01:56:40.453 回答
2

我经常使用这种模式:

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();
    }
  };
});
于 2015-10-24T00:00:10.270 回答
2

我意识到这个问题很老,但我在这里偶然发现了这种方法,所以我想我会加入一种更现代的 ko 方法。

您可以直接将属性添加到 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                                
    }
}

};​</p>

于 2016-12-29T15:38:06.167 回答
-2

通过在函数内部定义公共数据,我使用一个函数来为 init 和 update 创建一个公共范围。

于 2016-12-29T23:52:14.690 回答