【问题标题】:How do I create a definition list with d3.js?如何使用 d3.js 创建定义列表?
【发布时间】:2014-07-29 18:14:41
【问题描述】:

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

<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:我想使用&lt;dl&gt; 元素,因为它似乎是语义上表示键:值对的最合适的方式:

【问题讨论】:

  • 你最后做了什么?我刚刚遇到了这个问题,我找到了一个不涉及将 dt/dd 元素包装在 div 中的解决方案(并发布了an answer),但我很想知道您是否也找到了另一个解决方案。

标签: html d3.js key-value


【解决方案1】:

d3 v3.x 的解决方案;从 d3 4.0 起不再工作

我为同样的问题苦苦挣扎了一段时间。我发现 insert()enter() 选择的行为可以解决问题。这是基于插入或附加元素合并到更新选择中的输入选择之间的交互,插入与输入选择一起使用的方式。文档中的相关位:

selection.enter()

…当你进入更新选择时,输入选择合并到更新选择中 追加或插入。

selection.insert()

... 对于 enter 选择,可以省略 before 选择器,其中 case 输入元素将在下一个之前插入 更新选择中的以下兄弟,如果有的话。这使您可以 按照与绑定数据一致的顺序将元素插入 DOM。

结果是,如果你在 enter 选择中插入一些 dt 元素,它们将被合并到更新选择中。然后,如果您随后将一些 dd 元素插入到输入选择中,它们将“在更新选择中的下一个后续兄弟元素之前立即插入 ”;也就是说,他们会在他们关联的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] });
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"&gt;&lt;/script&gt;

【讨论】:

  • 这不再有效; selection.insert 现在(从 d3 4.0 开始)如果您不提供 before,则默认为 null,而不是在之前插入。
【解决方案2】:

当内容像您描述的那样简单时,最简单的方法 可能只是直接创建成对的 HTML 元素和 之后将数据绑定到它们。

此外,作为列表,一切都更容易——D3 的entries function 可以 轻松地将您的对象吹到对象列表中:

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/

【讨论】:

  • 您实际上可以使用输入选择和插入方法添加连续元素。我几天前才发现这一点(并添加了an answer)。这是一个奇怪的案例,但我认为它最终变得更干净了。
  • @JoshuaTaylor 哈哈!这很热。我会赞成你的回答。
  • 虽然这感觉有点笨拙(没有enterexit,只是在数据发生变化时报废和重建),但它适用于d3 4.0,而@JoshuaTaylor 则不行。
【解决方案3】:

我会这样做:

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 (more about implementation)。

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

【讨论】:

  • 非常感谢您的评论,效果很好。但是,该方法不提供数据绑定,因此无法使用.enter()、update 和.exit() 方法。
  • @Christophe 您实际上可以使用输入选择添加连续元素。例如,您可以var x = d3.select('body').append('dl').selectAll().data(...); x.enter().insert('dt'); x.enter().insert('dd');。我只是在遇到 OP 面临的同样问题时才发现这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-07
  • 1970-01-01
相关资源
最近更新 更多