自定义绑定 - init不断调用

时间:2015-08-26 10:44:24

标签: knockout.js ko-custom-binding

我一直在尝试使用自定义组件,然后在Knockout中使用自定义绑定来渲染小的可视化。我有这个工作,但意识到解决方案并不理想。我的自定义绑定应该通过使用转换处理数据的更改。

enter image description here

如果出现新项目,请说E,我希望它可以转换。我还需要在每次绑定更改时更新每个圆圈的绿色笔划。

我的问题是,当我的context绑定在下面的代码中更新时,整个绑定似乎重新初始化。我认为Knockout下面是删除前一个context的DOM并重新渲染整个批次 - 这会导致每个圆圈增长并触发新项目动画。

ko.components.register("context", {
    // Assume that the view model given to us is already observable, having had a ko.mapping.fromJS() applied or similar
    viewModel: function (vm) {
        this.context = vm;
    },
    template: '<div class="card context-card" data-bind="contextViz: context">\
                <!-- ko if: context && context.types.length === 0 -->\
                    <div>Please make a selection to view contextual information here.</div>\
                <!-- /ko -->\
               </div>\
               '
});

我想知道我能做些什么来防止这种情况发生。基本上我希望旧的context绑定只是更新,但我不确定是否有办法这样做。

我已添加了一个代码段来说明。每次更新时都会记录init called,我只想记录一次,update called多次记录。

&#13;
&#13;
var count = 0;

ko.bindingHandlers.contextViz = {
    init: function() {
        console.log("init called");
    },
    update: function() {
        console.log("update called");
    }
};

ko.components.register("context", {
    viewModel: function (vm) {
        this.context = vm;
    },
    template: '<div class="card context-card" data-bind="contextViz: context">'
});

var vm = {
   context: ko.observable({ count: count })
};

ko.applyBindings(vm);

setInterval(function() {
  vm.context({ count: count + 1 });  
}, 1000);
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="component: { name: 'context', params: $root.context }"></div>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:2)

因为您直接使用context属性,因为计算出的KO的params将在context更改时重新呈现整个计算。

通常的做法是传入一个具有params属性的对象,因此当此对象的属性发生更改时,组件不会完全重新渲染。

因此您需要将HTMl更改为:

<div data-bind="component: { name: 'context', params: { context: $root.context }}"></div>

在你的计算构造函数中只需写:

viewModel: function (params) {
    this.context = params.context;
},

&#13;
&#13;
var count = 0;

ko.bindingHandlers.contextViz = {
init: function() {
    document.getElementById("log").innerHTML += "init called\n";
},
update: function(e,v) {
    console.log(ko.unwrap(v())) // make a dependency so it will be called when the bound observable changes
    document.getElementById("log").innerHTML += "update called\n";
}
};

ko.components.register("context", {
viewModel: function (params) {
    this.context = params.context;
},
template: '<div class="card context-card" data-bind="contextViz: context">'
});

var vm = {
   context: ko.observable({ count: count })
};

ko.applyBindings(vm);

setInterval(function() {
  vm.context({ count: ++count });  
}, 1000);
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="component: { name: 'context', params: { context: $root.context }}"></div>
<div>log:</div>
<pre id="log"></pre>
&#13;
&#13;
&#13;