如果您希望 Knockout 与 d3 一起工作,您需要将敲除绑定应用于您创建的每个单独元素:
var data = [
{ "id": "1", "name": ko.observable("alpha") },
{ "id": "2", "name": ko.observable("bravo") },
{ "id": "3", "name": ko.observable("delta") }
];
d3.select("body").selectAll("span")
.data(data)
.enter()
.append("span")
.attr("data-bind", "text: name") // Applies the data binding attribute
.each(function (d) {
ko.applyBindings(d, this); // Sets up Knockout to work with the node
});
data[0].name('october');
您只需应用这些绑定一次 - 当您更改节点时,数据绑定仍然适用。事实上,如果您将绑定重新应用到已经存在的节点,您必须首先调用ko.cleanNode()
以摆脱第一个绑定。
如果您想在任何绑定上下文中从视图模型中获取此数据,请使用类似ko.dataFor()
获取父元素上的绑定的方法:
var data = ko.dataFor(d3.select("#parent-to-attach-to").node());
或显式订阅绑定:
viewModel.observableIWantToTrack.subscribe(function(newValue) {
// your d3 update code here, using newValue
}
或创建一个调用它的绑定处理程序:
ko.bindingHandler.whateverYouWantToCallYourHandler = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
// any initialization logic you need
},
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
// where you perform your actual updates
}
}
使用最适合您情况的任何解决方案。
还有一点需要注意:绑定不会重新评估,这就是您必须调用ko.applyBindings()
. 这对于普通绑定来说可能是可以的,比如if
和with
,尽管你会想要注意它们。它们不适用于foreach
绑定 - 如果您在插入数据绑定的 d3 元素后尝试评估 foreach 绑定,则 Knockout 将混合您放置的元素并导致很多问题。最好允许 d3 的本机数据连接行为做淘汰赛foreach
通常做的事情。