如何使用d3.js创建定义列表?

3

我正在尝试创建一个类似于这样的定义列表:

<dl>
   <dt>term1</dt>
   <dd>definition1</dd>
   <dt>term2</dt>
   <dd>definition2</dd>
   <dt>term3</dt>
   <dd>definition3</dd>
</dl>

使用以下形式的JSON:
{
  "term1":"definition1"
  "term1":"definition2"
  "term3":"definition3"
}

使用d3.js,最优雅的方法是什么?

PS:我想使用<dl>元素,因为它似乎是语义上表示键值对最合适的方式:


你最终是怎么处理这个问题的?我刚遇到了这个问题,找到了一个解决方案,不需要将dt/dd元素包装在div中(并发布了答案),但我很想知道你是否也找到了其他的解决方案。 - Joshua Taylor
3个回答

8

d3 v3.x的解决方案;从d3 4.0开始不再适用

我也曾经遇到过同样的问题。我找到了一种使用 insert()enter() 选择器的方法来解决这个问题。这是基于enter选择器插入或附加元素与更新选择器合并的交互方式,以及insert函数与enter选择器的工作方式。文档中相关部分如下:

selection.enter()

…当您附加或插入时,enter选择器会合并到更新选择器中。

selection.insert()

…对于enter选择器,before选择器可以省略,在这种情况下,如果有的话,输入元素将立即插入到更新选择器中的下一个后续兄弟节点之前。这允许您按照绑定数据的顺序将元素插入到DOM中。

结果是,如果您将一些dt元素插入到enter选择器中,它们将合并到更新选择器中。然后,如果您将一些dd元素插入到enter选择器中,它们将会“立即插入到更新选择器中的下一个后续兄弟节点之前”,也就是说,它们将紧跟在其相关的dt元素之后。

var data = { a: 1, b: 2, c: 3 };
var dl = d3.select("body").append("dl").selectAll().data(Object.keys(data));
dl.enter().insert("dt").text(function(key) { return key });
dl.enter().insert("dd").text(function(key) { return data[key] });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>


这个已经不再起作用了;selection.insert现在(自d3 4.0版本)默认为null,如果您没有给出“before”,而不是在之前插入。 - Vivian

3

如果内容像你所描述的那样简单,最简单的方法可能是直接创建成对的HTML元素,然后将数据绑定到它们上面。

另外,将所有内容都转换为列表会更容易--D3的entries函数可以轻松地将您的对象转换为对象列表:

var pairs = {
  "term1":"definition1",
  "term2":"definition2",
  "term3":"definition3"
};
var pairlist = d3.entries(pairs);  // [{"key":"term1", "value":"definition1"}, etc... ]

var dl = d3.select("dl").html( new Array(pairlist.length + 1).join("<dt/><dd/>") );

dl.selectAll("dt").data(pairlist).html(function(d) { return d.key; });
dl.selectAll("dd").data(pairlist).html(function(d) { return d.value; });

JsFiddle: http://jsfiddle.net/slushy/bbh6a4w0/


你实际上可以使用回车选择和插入方法来添加连续的元素。我几天前才发现这个方法(并添加了一个答案)。这可能有点奇怪,但我认为它最终会变得更加简洁。 - Joshua Taylor
@JoshuaTaylor 哈哈!太棒了。我会给你的答案点赞。 - slushy
虽然这种方法感觉有些笨拙(没有“进入”或“退出”,只是在数据更改时进行抓取和重建),但它适用于d3 4.0,而@JoshuaTaylor的方法则不行。 - Vivian

-1

这是我的做法:

list = {
  "term1":"definition1",
  "term2":"definition2",
  "term3":"definition3"
}

dl = d3.select('body').append('dl')
for(var key in list) {
    dl.append('dt').text(key)
    dl.append('dd').text(list[key])
}

JsFiddle: http://jsfiddle.net/chrisJamesC/RZdQw/

如果你想更加专注于d3方面的话,你可以使用selections关于实现的更多信息)。

顺便说一下,使用数组可能比json对象更容易表示列表。


2
非常感谢您的评论,它非常有效。然而,这种方法不提供数据绑定,因此无法使用.enter()update.exit()方法。 - leonard vertighel
1
@Christophe,您实际上可以使用enter选择器添加连续的元素。例如,您可以使用var x = d3.select('body').append('dl').selectAll().data(...); x.enter().insert('dt'); x.enter().insert('dd');。当我面临与OP相同的问题时,我刚刚发现了这一点。 - Joshua Taylor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接