考虑这个简单的 HTML 块:
<div id="somediv">
<btn id="somebutton">Abc</btn>
<div class="nested">
<span id="span1">Blah blah blah</span>
<span id="span2">Bleh bleh bleh</span>
</div>
</div>
Run Code Online (Sandbox Code Playgroud)
我想使用 D3JS 动态地重新创建它。
这适用于此目的:
(function() {
var somediv = d3.select( 'body' ).append( 'div' ).attr( 'id', 'somediv' );
somediv.append( 'btn' )
.attr( 'id', 'somebutton' )
.html( 'Abc' );
var nested = somediv.append( 'div' )
.attr( 'class', 'nested' );
nested.append( 'span' ).attr( 'id', 'span1' ).html( 'Blah blah blah' );
nested.append( 'span' ).attr( 'id', 'span2' ).html( 'Bleh bleh bleh' );
})();
Run Code Online (Sandbox Code Playgroud)
……然而,它非常冗长,有四个命令和两个临时变量……最重要的是,它不容易阅读——不喜欢它。
我正在寻找一种在单个命令中执行此操作的方法。
到目前为止,我有这个:
d3.select( 'body' )
.append( 'div' )
.attr( 'id', 'somediv' )
.append( 'btn' )
.attr( 'id', 'somebutton' )
.html( 'Abc' )
.append( 'div' )
.attr( 'class', 'nested' )
.append( 'span' ).attr( 'id', 'span1' ).html( 'Blah blah blah' )
.append( 'span' ).attr( 'id', 'span2' ).html( 'Bleh bleh bleh' );
Run Code Online (Sandbox Code Playgroud)
…然而(正如预期的那样),这会导致不断的嵌套(即:span2 在 span1 中,在 div 中,在 btn 中,在 #somediv 中。)
D3 JS API 中有什么东西可以让我返回(到)父元素以继续从它追加?
You could do this in a single command, but it would likely become less readable than the multiple commands you have. For example:
d3.select("body")
.append("div")
.each(function() {
d3.select(this).append("button").html("button")
d3.select(this).append("div")
.each(function() {
d3.select(this).append("span").text("span")
d3.select(this).append("span").text("span")
})
})
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
Run Code Online (Sandbox Code Playgroud)
This certainly works, as you can see, but it might not be considered as readable because it is an unusual d3 pattern, especially if you need to share the code with others that are familiar with d3. The readability would likely degrade as we nest further too.
You can also use a method I suggested in a previous answer, and create a selection.appendSibling
method. With the extra verbosity of creating the method, you can get something that looks a bit more clean:
// modify d3.selection so that we can append a sibling
d3.selection.prototype.appendSibling = function(type) {
var siblings = this.nodes().map(function(n) {
return n.parentNode.insertBefore(document.createElement(type), n.nextSibling);
})
return d3.selectAll(siblings).data(this.data());
}
d3.select("body")
.append("div")
.append("button").html("button")
.appendSibling("div") // append a sibling div to the button
.append("span").text("span1")
.appendSibling("span").text("span2"); // append a sibling span to the first span
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
Run Code Online (Sandbox Code Playgroud)
But I don't suggest this approach - it is not clear what selection is being manipulated on each line. It was intended to be used when working with paired elements, such as dl
and dd
elements.
While the above two work, and you could also use an enter cycle to append the two spans rather than independent append statements, I still suggest breaking the code into multiple segments as you had originally used:
var container = d3.select("body").append("div");
var button = container.append("button").html("button");
var spans = container.append("div")
.selectAll(null)
.data([1,2])
.enter()
.append("span")
.text(function(d) { return "span"+ d; })
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
Run Code Online (Sandbox Code Playgroud)
(of course, we could skip the var declarations for both spans and button to keep things tighter)
Or, more in keeping with the first two snippets:
var container = d3.select("body").append("div");
var button = container.append("button").html("button");
var div = container.append("div");
var span1 = div.append("span").text("span1")
var span2 = div.append("span").text("span2");
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
Run Code Online (Sandbox Code Playgroud)
(Again, I could remove the unnecessary var declarations if it is considered noise)
These last two snippets are actually shorter than the first one.
While this strays from the question, I believe these last two snippets are favorable for several reasons: