Skip to content

D3.js - 选择集 (Selections)

选择集是 D3.js 中的一个基本概念。它们允许您使用 CSS 选择器从网页中选择现有的 DOM (文档对象模型) 元素。元素被选中后,D3 提供了强大的 API 来修改它们的属性、样式、内容,甚至可以追加或删除元素,通常这与数据集相关联。理解选择集是掌握 D3 的关键。

D3.js 提供了两种主要的元素选择方法:

  • d3.select(selector): 选择与指定的 CSS selector 匹配的第一个 DOM 元素。如果多个元素匹配,选择集中只包含在文档中遇到的第一个匹配元素。
  • d3.selectAll(selector): 选择与指定的 CSS selector 匹配的所有 DOM 元素。这会返回一个包含所有匹配元素的选择集,如果没有匹配元素,则返回一个空选择集。

如果您熟悉 jQuery 选择器,D3.js 选择器的工作方式类似。

d3.select() 方法使用标准的 CSS 选择器来查找元素。您可以通过以下方式选择:

  • 标签名: 例如,div、h1、p、span。
  • 类名: 例如,.my-class(以点号开头)。
  • ID: 例如,#my-id(以井号开头)。

我们来看一下每种方式的示例。

要选择页面上的第一个 <div> 元素:

const firstDiv = d3.select("div");

示例:修改第一个 div 的文本。

<!DOCTYPE html>
<html>
<head>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<div>原始文本 1</div>
<div>原始文本 2</div>
<script>
d3.select("div").text("来自 D3 的问候!这是第一个 div。");
</script>
</body>
</html>

在浏览器中,只有第一个 div 的内容会改变。

要选择具有特定类的元素,请使用点号 . 作为前缀。

// Selects the first element with class 'myclass'
const myElement = d3.select(".myclass");

示例:

<!DOCTYPE html>
<html>
<head>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<p>另一个段落。</p>
<div class="myclass">myclass div 中的文本。</div>
<span class="myclass">myclass span 中的文本。</span>
<script>
d3.select(".myclass").style("color", "blue"); // 只有这个 div 会变成蓝色
</script>
</body>
</html>

ID 在 HTML 文档中应该是唯一的。使用井号 # 作为前缀,按 ID 选择元素。

// Selects the element with ID 'uniqueElement'
const uniqueElem = d3.select("#uniqueElement");

示例:

<!DOCTYPE html>
<html>
<head>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<div id="greeting">你好世界!</div>
<script>
d3.select("#greeting").html("**来自 D3 的问候!**");
</script>
</body>
</html>

D3 选择集提供了 .append() 和 .text()(或 .html())等方法,用于向 DOM 添加新元素或修改它们的内容。这些方法通常会返回新的选择集,从而允许使用方法链式调用。

.append(name) 方法将一个具有指定标签 name(例如 ‘div’, ‘span’, ‘svg:rect’)的新元素作为每个被选中元素的最后一个子元素追加进去。它返回一个包含新追加元素的新的选择集。

示例:

<!DOCTYPE html>
<html>
<head>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<div class="container">容器 div。</div>
<script>
d3.select("div.container").append("span");
// 这会在 div 内部添加一个空的 <span>。
// HTML 将变成: <div class="container">容器 div。<span></span></div>
</script>
</body>
</html>

.text(value) 方法设置被选中元素的文本内容。如果 value 是一个常量,所有被选中元素都将获得相同的文本。如果 value 是一个函数,它将对每个被选中元素进行评估。

链式调用 .append() 和 .text():

<!DOCTYPE html>
<html>
<head>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<div class="message">初始消息。</div>
<script>
d3.select("div.message")
.append("span") // 追加一个 span,返回该 span 的选择集
.text(" -- Added by D3.js"); // 设置新 span 的文本
</script>
</body>
</html>

结果是:<div class="message">初始消息。<span> -- Added by D3.js</span></div>。

D3.js 广泛使用方法链式调用。不使用链式调用的同一脚本将是:

const messageDiv = d3.select("div.message");
const newSpan = messageDiv.append("span");
newSpan.text(" -- Added by D3.js");

D3 提供了 .html()、.attr() 和 .style() 等方法来修改被选中元素的内容、属性和样式。

.html(value) 方法设置被选中元素的内部 HTML 内容。在使用不可信的用户提供的内容时要小心,因为可能存在 XSS 漏洞。

<!DOCTYPE html>
<html>
<head>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<div class="content">占位符</div>
<script>
d3.select(".content").html("来自 D3.js 的新 **HTML** 内容");
</script>
</body>
</html>

.attr(name, value) 方法将所有被选中元素的属性 name 设置为指定的 value。如果 value 是 null,则该属性将被移除。

<!DOCTYPE html>
<html>
<head>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<a href="#old-link">旧链接</a>
<script>
d3.select("a").attr("href", "https://d3js.org").attr("target", "_blank");
</script>
</body>
</html>

.style(name, value) 方法将 CSS 样式属性 name 设置为指定的 value。可以指定一个可选的 priority(例如,“important”)。

<!DOCTYPE html>
<html>
<head>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<p class="highlightable">这段文字将被设置样式。</p>
<script>
d3.select(".highlightable")
.style("color", "red")
.style("font-weight", "bold");
</script>
</body>
</html>

.classed(names, active) 方法专门用于管理 CSS 类。names 是一个由空格分隔的类名字符串。active 是一个布尔值:true 添加类,false 移除类。如果 active 是一个函数,它将对每个元素进行评估。

  • 添加类: d3.select(".my-element").classed("active highlighted", true);
  • 移除类: d3.select(".my-element").classed("active", false);
  • 检查类是否存在(在第一个元素上): const isActive = d3.select(".my-element").classed("active");
  • 切换类: element.classed("toggled-class", !element.classed("toggled-class"));

d3.selectAll(selector) 方法选择所有匹配选择器的元素。当您对 d3.selectAll() 返回的选择集应用修改方法(如 .attr()、.style()、.text())时,更改会应用于该选择集中的每个元素。

<!DOCTYPE html>
<html>
<head>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
.item { padding: 5px; margin: 2px; border: 1px solid #eee; }
</style>
</head>
<body>
<div class="item">项目 1</div>
<p class="item">项目 2 (段落)</p>
<div class="item">项目 3</div>
<script>
d3.selectAll(".item")
.style("background-color", "lightblue")
.append("strong")
.text(" - 已处理!");
</script>
</body>
</html>

在这个示例中,所有具有类名 item 的元素(两个 div 和一个 p)都将获得浅蓝色背景,并且其内容后面会追加粗体的 ” - 已处理!”。

选择集是通往 D3 数据绑定能力的门户,通过数据绑定,这些 DOM 操作变为数据驱动,构成了 D3 强大能力的核心。