我正在尝试关注 Mike Bostock seems to indicate is a best practice ,即将您的 selectAll()
分配给一个变量,然后分离出更新、enter()
和 exit()
,但是我我注意到 V4 中存在我无法解释的差异。
考虑以下工作代码:
// Bind an array of users to the #users div
var userNodes = d3.select("#users").selectAll("li")
.data(d3.values(users))
// Add LIs for any new users
.enter()
.append("li");
var userMessageGraph = userNodes.selectAll("span")
.data(function(d){ return [d.name]; })
.enter().append("span")
.text(function(d){ return d; });
这会创建一个空的 LI,然后在其中附加一个带有用户名的 SPAN。 (顺便说一句,如果这就是我想要的,我相信有更好的方法,但这只是为了说明我的观点而减少其他内容。如果愿意,请耐心等待。)
现在我尝试通过对存储的变量运行 enter()
来使其适应我对上述最佳实践的解释,并且子元素失去了与父数据的链接。我得到一个空列表。
// Bind an array of users to the #users div
var userNodes = d3.select("#users").selectAll("li")
.data(d3.values(users));
// Add LIs for any new users
userNodes.enter()
.append("li");
var userMessageGraph = userNodes.selectAll("span")
.data(function(d){ return [d.name]; })
.enter().append("span")
.text(function(d){ return d; });
更新1
嗯,看了之后 [~Gerardo Furtado]的 react ,我以为我得到了。显然,我在这里遗漏了一个基本原则。
这是我的代码,它尝试使用 merge()
来确保数据被传送到子元素,但没有任何乐趣:
var userNodes = d3.select("#users").selectAll("li")
.data(d3.values(users));
// Add LIs for any new users
userNodes.enter()
.append("li")
// New for V4, merge back the original set to get the data
.merge(userNodes);
var userMessageGraph = userNodes.selectAll("span")
.data(function(d){ return [d.name]; })
.enter().append("span")
.text(function(d){ return d; });
最佳答案
我想您使用的是 d3 v4.x。在那种情况下,这是预期的行为。
这就是正在发生的事情:userNodes
是数据绑定(bind)变量:
var userNodes = d3.select("#users").selectAll("li")
.data(d3.values(users));
然后,你写:
userNodes.enter()
.append("li");
这就是“输入”选项。
在 d3 v3.x 中,输入选择神奇地修改了您的原始变量,将其变成这样:
var userNodes = d3.select("#users").selectAll("li")
.data(d3.values(users));
.enter()
.append("li");
但是,在 d3 v4.x 中,您的原始变量仍然只是一个数据绑定(bind)选择:
var userNodes = d3.select("#users").selectAll("li")
.data(d3.values(users));
所以,如果我们重写你的 userMessageGraph
考虑到链接,这就是它的真实情况:
var userMessageGraph = d3.select("#users")//here userNode starts
.selectAll("li")
.data(d3.values(users))//this is where userNode ends
.selectAll("span")
.data(function(d){ return [d.name]; })
.enter().append("span")
.text(function(d){ return d; });
您可以看到 <li>
的“输入”选择, 这是...
.enter()
.append("li")
...丢失了。
编辑:此编辑解决了 OP 的新代码:
var userNodes = d3.select("#users").selectAll("li")
.data(d3.values(users));
// Add LIs for any new users
userNodes.enter()
.append("li")
// New for V4, merge back the original set to get the data
.merge(userNodes);
这行不通是有原因的:merge
函数...
...returns a new selection merging this selection with the specified other selection. The returned selection has the same number of groups and the same parents as this selection. (emphasis mine)
作为userNodes
是一个空选择,这将不起作用。您可以反转逻辑:
var userNodes = d3.select("#users").selectAll("li")
.data(d3.values(users));
var userNodesEnter = userNodes.enter()
.append("li");
var userNodesUpdate = userNodesEnter.merge(userNodes);
var userMessageGraph = userNodesUpdate.selectAll("span")
.data(function(d) {
return [d.name];
})
.enter().append("span")
.text(function(d) {
return d;
});
关于javascript - 为什么D3.js数据在enter()链式调用时只对子节点可用,不单独调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41072291/