如何使用d3.js创建<dl>

Mat*_*hew 6 javascript d3.js

我想dl使用d3.js从一些数据列表中创建一系列标签.

我想出的代码是这样的:

var x=d3.select("body")
    .append('ol')
    .selectAll('li')
    .data(data)
    .enter()
    .append('li')
    .append('dl')
    .selectAll()
    .data(d=>Object.entries(d.volumeInfo)).enter();

x.append('dt')
    .text(d=>d[0]);

x.append('dd')
    .text(d=>d[1]);
Run Code Online (Sandbox Code Playgroud)

其中data是一个对象数组.除了元素的顺序不正确外,一切正常.

这是我设法得到的订单:

<dl>
    <dt>key1</dt>
    <dt>key2</dt>
    <dd>value1</dd>
    <dd>value2</dd>
</dl>
Run Code Online (Sandbox Code Playgroud)

但它应该是这样的:

<dl>
    <dt>key1</dt>
    <dd>value1</dd>
    <dt>key2</dt>
    <dd>value2</dd>
</dl>
Run Code Online (Sandbox Code Playgroud)

我已经做了相当多的谷歌搜索,没有回答这个问题,至少不是在v5中工作的方式,或者不是有多个dt/dd对.

这似乎是d3.js应该能做的基本事情.

And*_*eid 5

在您的解决方案:

x.append('dt')
    .text(d=>d[0]);

x.append('dd')
    .text(d=>d[1]);
Run Code Online (Sandbox Code Playgroud)

附加enter().append()循环的所有元素将按照它们的附加顺序附加到父级,对于您运行的顺序如下:首先是所有dts,然后是所有dds,如您所见.由enter语句创建的占位符节点(这些不是附加元素)不会以您可能期望的方式嵌套子节点.

尽管d3不包括使用方法实现selection.append()所需内容的方法,只需简单的方法,但使用标准d3方法和额外的一两步可以很容易地实现所需的行为.或者,我们可以自己将该功能构建到d3.selection中.

对于我的回答,我将完成一个使用您的数据结构并输入模式的示例,但是首先我将简化嵌套 - 而不是嵌套的附加,我只是演示了几种可能的方法来附加有序的兄弟.首先,我还简化了数据结构,但原理保持不变.


第一种方法可能是最直接的:使用selection.each()函数.使用输入选择(使用父级或输入的占位符),使用each方法追加两个单独的元素:

var data = [
{name:"a",description:"The first letter"},
{name:"b",description:"The second letter"}
];


d3.select("body")
  .selectAll(null)
  .data(data)
  .enter()
  .each(function(d) {
	var selection = d3.select(this);
	
	// append siblings:
	selection.append("dt")
	  .html(function(d) { return d.name; });
	selection.append("dd")
	  .html(function(d) { return d.description; })
    
})
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)


但是,也许更优雅的选择是挖掘d3.selection()并用它来玩具给我们一些新的行为.下面我添加了一个selection.appendSibling()方法,它允许您在选择中的每个项目的正下方追加一个配对的兄弟元素:

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());
}
Run Code Online (Sandbox Code Playgroud)

它选择每个节点,在指定类型中创建一个新的配对兄弟节点(每个节点紧接在DOM中的原始节点之后),然后将新节点放在d3选择中并绑定数据.这允许您将方法链接到它上以设置元素的样式等,并允许您访问绑定的基准.请参阅下面的操作:

// 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());
}

var data = [
    {name:"a",description:"The first letter"},
    {name:"b",description:"The second letter"}
    ];

d3.select("body")
  .selectAll(null)
  .data(data)
  .enter()
  .append("dt")
  .html(function(d) { return d.name; })
  .appendSibling("dd")  // append siblings
  .html(function(d) { return d.description; })  // modify the siblings
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)

当然,将兄弟姐妹分开选择是很明智的,这样你就可以管理每个兄弟姐妹的更新/进入/退出等.

这个方法非常容易应用于您的示例,这是一个嵌套的解决方案,使用的结构与您期望的结果和appendSibling方法一样:

// 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());
}

var data = [
 {volumeInfo: {"a":1,"b":2,"c":3}},
 {volumeInfo: {"?":1,"?":2}}
]

var items = d3.select("body")
    .append('ol')
    .selectAll('li')
    .data(data)
    .enter()
    .append('li')
    .append('dl')
    .selectAll()
    .data(d=>Object.entries(d.volumeInfo)).enter();
  
var dt = items.append("dt")
  .text(function(d) { return d[0]; })
  
var dd = dt.appendSibling("dd")
  .text(function(d) { return d[1]; })
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)